summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-04-11 15:54:21 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-04-11 15:54:21 -0700
commit65311d813461295c85f338d99de7c7b8fcccbb9b (patch)
tree9419ad38e9730faa1dbe2794e4ac0bb35512bf3b
parent9ec7dfaf2cc0e5000dec931bde41f17c7eb203db (diff)
downloadlinux-3.10-65311d813461295c85f338d99de7c7b8fcccbb9b.tar.gz
linux-3.10-65311d813461295c85f338d99de7c7b8fcccbb9b.tar.bz2
linux-3.10-65311d813461295c85f338d99de7c7b8fcccbb9b.zip
irqchip patches added
-rw-r--r--patches.misc/0001-irqchip-add-basic-infrastructure.patch207
-rw-r--r--patches.misc/0002-irqdomain-augment-add_simple-to-allocate-descs.patch83
-rw-r--r--patches.misc/0003-irqdomain-stop-screaming-about-preallocated-irqdescs.patch30
-rw-r--r--patches.misc/0004-irqchip-Renesas-INTC-External-IRQ-pin-driver.patch548
-rw-r--r--patches.misc/0005-irqchip-intc-irqpin-Cache-mapped-IRQ.patch128
-rw-r--r--patches.misc/0006-ARM-shmobile-irq_pin-for-static-IRQ-pin-assignment.patch28
-rw-r--r--patches.misc/0007-ARM-shmobile-INTC-External-IRQ-pin-driver-on-r8a7779.patch155
-rw-r--r--patches.misc/0008-irqchip-intc-irqpin-Whitespace-fixes.patch34
-rw-r--r--patches.misc/0009-irqchip-intc-irqpin-Add-force-comments.patch41
-rw-r--r--patches.misc/0010-irqchip-intc-irqpin-Make-use-of-devm-functions.patch124
-rw-r--r--patches.misc/0011-irqchip-intc-irqpin-GPL-header-for-platform-data.patch40
-rw-r--r--patches.misc/0012-irqchip-Renesas-IRQC-driver.patch395
-rw-r--r--patches.misc/0013-ARM-shmobile-Make-r8a7779-INTC-irqpin-platform-data-.patch29
-rw-r--r--patches.misc/0014-irqchip-intc-irqpin-Initial-DT-support.patch48
-rw-r--r--patches.misc/0015-irqchip-irqc-Add-DT-support.patch46
-rw-r--r--series15
16 files changed, 1951 insertions, 0 deletions
diff --git a/patches.misc/0001-irqchip-add-basic-infrastructure.patch b/patches.misc/0001-irqchip-add-basic-infrastructure.patch
new file mode 100644
index 00000000000..e2743479ecf
--- /dev/null
+++ b/patches.misc/0001-irqchip-add-basic-infrastructure.patch
@@ -0,0 +1,207 @@
+From ec84d795c3d26160bba23ec9f37e1d6e484afc8a Mon Sep 17 00:00:00 2001
+From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Date: Tue, 20 Nov 2012 23:00:52 +0100
+Subject: irqchip: add basic infrastructure
+
+With the recent creation of the drivers/irqchip/ directory, it is
+desirable to move irq controller drivers here. At the moment, the only
+driver here is irq-bcm2835, the driver for the irq controller found in
+the ARM BCM2835 SoC, present in Rasberry Pi systems. This irq
+controller driver was exporting its initialization function and its
+irq handling function through a header file in
+<linux/irqchip/bcm2835.h>.
+
+When proposing to also move another irq controller driver in
+drivers/irqchip, Rob Herring raised the very valid point that moving
+things to drivers/irqchip was good in order to remove more stuff from
+arch/arm, but if it means adding gazillions of headers files in
+include/linux/irqchip/, it would not be very nice.
+
+So, upon the suggestion of Rob Herring and Arnd Bergmann, this commit
+introduces a small infrastructure that defines a central
+irqchip_init() function in drivers/irqchip/irqchip.c, which is meant
+to be called as the ->init_irq() callback of ARM platforms. This
+function calls of_irq_init() with an array of match strings and init
+functions generated from a special linker section.
+
+Note that the irq controller driver initialization function is
+responsible for setting the global handle_arch_irq() variable, so that
+ARM platforms no longer have to define the ->handle_irq field in their
+DT_MACHINE structure.
+
+A global header, <linux/irqchip.h> is also added to expose the single
+irqchip_init() function to the reset of the kernel.
+
+A further commit moves the BCM2835 irq controller driver to this new
+small infrastructure, therefore removing the include/linux/irqchip/
+directory.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Reviewed-by: Stephen Warren <swarren@wwwdotorg.org>
+Reviewed-by: Rob Herring <rob.herring@calxeda.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+[rob.herring: reword commit message to reflect use of linker sections.]
+Signed-off-by: Rob Herring <rob.herring@calxeda.com>
+(cherry picked from commit f6e916b82022cba67bdd0ec7df84e2bce2ef3f73)
+
+Conflicts:
+ drivers/Kconfig
+ drivers/Makefile
+ drivers/irqchip/Kconfig
+ drivers/irqchip/Makefile
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/Kconfig | 1 +
+ drivers/Makefile | 2 ++
+ drivers/irqchip/Kconfig | 3 +++
+ drivers/irqchip/Makefile | 1 +
+ drivers/irqchip/irqchip.c | 30 ++++++++++++++++++++++++++++++
+ drivers/irqchip/irqchip.h | 29 +++++++++++++++++++++++++++++
+ include/asm-generic/vmlinux.lds.h | 12 +++++++++++-
+ include/linux/irqchip.h | 16 ++++++++++++++++
+ 8 files changed, 93 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/irqchip/Kconfig
+ create mode 100644 drivers/irqchip/Makefile
+ create mode 100644 drivers/irqchip/irqchip.c
+ create mode 100644 drivers/irqchip/irqchip.h
+ create mode 100644 include/linux/irqchip.h
+
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -140,4 +140,5 @@ source "drivers/virt/Kconfig"
+
+ source "drivers/devfreq/Kconfig"
+
++source "drivers/irqchip/Kconfig"
+ endmenu
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -134,3 +134,5 @@ obj-$(CONFIG_VIRT_DRIVERS) += virt/
+ obj-$(CONFIG_HYPERV) += hv/
+
+ obj-$(CONFIG_PM_DEVFREQ) += devfreq/
++
++obj-y += irqchip/
+--- /dev/null
++++ b/drivers/irqchip/Kconfig
+@@ -0,0 +1,3 @@
++config IRQCHIP
++ def_bool y
++ depends on OF_IRQ
+--- /dev/null
++++ b/drivers/irqchip/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_IRQCHIP) += irqchip.o
+--- /dev/null
++++ b/drivers/irqchip/irqchip.c
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2012 Thomas Petazzoni
++ *
++ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/init.h>
++#include <linux/of_irq.h>
++
++#include "irqchip.h"
++
++/*
++ * This special of_device_id is the sentinel at the end of the
++ * of_device_id[] array of all irqchips. It is automatically placed at
++ * the end of the array by the linker, thanks to being part of a
++ * special section.
++ */
++static const struct of_device_id
++irqchip_of_match_end __used __section(__irqchip_of_end);
++
++extern struct of_device_id __irqchip_begin[];
++
++void __init irqchip_init(void)
++{
++ of_irq_init(__irqchip_begin);
++}
+--- /dev/null
++++ b/drivers/irqchip/irqchip.h
+@@ -0,0 +1,29 @@
++/*
++ * Copyright (C) 2012 Thomas Petazzoni
++ *
++ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#ifndef _IRQCHIP_H
++#define _IRQCHIP_H
++
++/*
++ * This macro must be used by the different irqchip drivers to declare
++ * the association between their DT compatible string and their
++ * initialization function.
++ *
++ * @name: name that must be unique accross all IRQCHIP_DECLARE of the
++ * same file.
++ * @compstr: compatible string of the irqchip driver
++ * @fn: initialization function
++ */
++#define IRQCHIP_DECLARE(name,compstr,fn) \
++ static const struct of_device_id irqchip_of_match_##name \
++ __used __section(__irqchip_of_table) \
++ = { .compatible = compstr, .data = fn }
++
++#endif
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -149,6 +149,15 @@
+ #define TRACE_SYSCALLS()
+ #endif
+
++#ifdef CONFIG_IRQCHIP
++#define IRQCHIP_OF_MATCH_TABLE() \
++ . = ALIGN(8); \
++ VMLINUX_SYMBOL(__irqchip_begin) = .; \
++ *(__irqchip_of_table) \
++ *(__irqchip_of_end)
++#else
++#define IRQCHIP_OF_MATCH_TABLE()
++#endif
+
+ #define KERNEL_DTB() \
+ STRUCT_ALIGN(); \
+@@ -493,7 +502,8 @@
+ DEV_DISCARD(init.rodata) \
+ CPU_DISCARD(init.rodata) \
+ MEM_DISCARD(init.rodata) \
+- KERNEL_DTB()
++ KERNEL_DTB() \
++ IRQCHIP_OF_MATCH_TABLE()
+
+ #define INIT_TEXT \
+ *(.init.text) \
+--- /dev/null
++++ b/include/linux/irqchip.h
+@@ -0,0 +1,16 @@
++/*
++ * Copyright (C) 2012 Thomas Petazzoni
++ *
++ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#ifndef _LINUX_IRQCHIP_H
++#define _LINUX_IRQCHIP_H
++
++void irqchip_init(void);
++
++#endif
diff --git a/patches.misc/0002-irqdomain-augment-add_simple-to-allocate-descs.patch b/patches.misc/0002-irqdomain-augment-add_simple-to-allocate-descs.patch
new file mode 100644
index 00000000000..bdfe77e4655
--- /dev/null
+++ b/patches.misc/0002-irqdomain-augment-add_simple-to-allocate-descs.patch
@@ -0,0 +1,83 @@
+From 6d044f57896d098e437879dae9993aefe7ad60e0 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Thu, 27 Sep 2012 14:59:39 +0200
+Subject: irqdomain: augment add_simple() to allocate descs
+
+Currently we rely on all IRQ chip instances to dynamically
+allocate their IRQ descriptors unless they use the linear
+IRQ domain. So for irqdomain_add_legacy() and
+irqdomain_add_simple() the caller need to make sure that
+descriptors are allocated.
+
+Let's slightly augment the yet unused irqdomain_add_simple()
+to also allocate descriptors as a means to simplify usage
+and avoid code duplication throughout the kernel.
+
+We warn if descriptors cannot be allocated, e.g. if a
+platform has the bad habit of hogging descriptors at boot
+time.
+
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Grant Likely <grant.likely@secretlab.ca>
+Cc: Paul Mundt <lethal@linux-sh.org>
+Cc: Russell King <linux@arm.linux.org.uk>
+Cc: Lee Jones <lee.jones@linaro.org>
+Reviewed-by: Rob Herring <rob.herring@calxeda.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+(cherry picked from commit 2854d167cc545d0642277bf8b77f972a91146fc6)
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ kernel/irq/irqdomain.c | 33 ++++++++++++++++++++++++++++-----
+ 1 file changed, 28 insertions(+), 5 deletions(-)
+
+--- a/kernel/irq/irqdomain.c
++++ b/kernel/irq/irqdomain.c
+@@ -148,7 +148,8 @@ static unsigned int irq_domain_legacy_re
+ * @host_data: Controller private data pointer
+ *
+ * Allocates a legacy irq_domain if irq_base is positive or a linear
+- * domain otherwise.
++ * domain otherwise. For the legacy domain, IRQ descriptors will also
++ * be allocated.
+ *
+ * This is intended to implement the expected behaviour for most
+ * interrupt controllers which is that a linear mapping should
+@@ -162,11 +163,33 @@ struct irq_domain *irq_domain_add_simple
+ const struct irq_domain_ops *ops,
+ void *host_data)
+ {
+- if (first_irq > 0)
+- return irq_domain_add_legacy(of_node, size, first_irq, 0,
++ if (first_irq > 0) {
++ int irq_base;
++
++ if (IS_ENABLED(CONFIG_SPARSE_IRQ)) {
++ /*
++ * Set the descriptor allocator to search for a
++ * 1-to-1 mapping, such as irq_alloc_desc_at().
++ * Use of_node_to_nid() which is defined to
++ * numa_node_id() on platforms that have no custom
++ * implementation.
++ */
++ irq_base = irq_alloc_descs(first_irq, first_irq, size,
++ of_node_to_nid(of_node));
++ if (irq_base < 0) {
++ WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
++ first_irq);
++ irq_base = first_irq;
++ }
++ } else
++ irq_base = first_irq;
++
++ return irq_domain_add_legacy(of_node, size, irq_base, 0,
+ ops, host_data);
+- else
+- return irq_domain_add_linear(of_node, size, ops, host_data);
++ }
++
++ /* A linear domain is the default */
++ return irq_domain_add_linear(of_node, size, ops, host_data);
+ }
+
+ /**
diff --git a/patches.misc/0003-irqdomain-stop-screaming-about-preallocated-irqdescs.patch b/patches.misc/0003-irqdomain-stop-screaming-about-preallocated-irqdescs.patch
new file mode 100644
index 00000000000..f9444d9ef35
--- /dev/null
+++ b/patches.misc/0003-irqdomain-stop-screaming-about-preallocated-irqdescs.patch
@@ -0,0 +1,30 @@
+From cfb1c1582aada77bfe7294b7ec4f60c6bf74ceac Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Tue, 27 Nov 2012 01:20:32 +0100
+Subject: irqdomain: stop screaming about preallocated irqdescs
+
+In the simple irqdomain: don't shout warnings to the user,
+there is no point. An informational print is sufficient.
+
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
+(cherry picked from commit d202b7b970b2a21278505c2467919fd441a7b6c8)
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ kernel/irq/irqdomain.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/kernel/irq/irqdomain.c
++++ b/kernel/irq/irqdomain.c
+@@ -177,8 +177,8 @@ struct irq_domain *irq_domain_add_simple
+ irq_base = irq_alloc_descs(first_irq, first_irq, size,
+ of_node_to_nid(of_node));
+ if (irq_base < 0) {
+- WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
+- first_irq);
++ pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
++ first_irq);
+ irq_base = first_irq;
+ }
+ } else
diff --git a/patches.misc/0004-irqchip-Renesas-INTC-External-IRQ-pin-driver.patch b/patches.misc/0004-irqchip-Renesas-INTC-External-IRQ-pin-driver.patch
new file mode 100644
index 00000000000..c64f7378e0c
--- /dev/null
+++ b/patches.misc/0004-irqchip-Renesas-INTC-External-IRQ-pin-driver.patch
@@ -0,0 +1,548 @@
+From a19094353a6fc670c1ff007a56698a088bcb2cbd Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Mon, 18 Feb 2013 23:28:34 +0900
+Subject: irqchip: Renesas INTC External IRQ pin driver
+
+This patch adds a driver for external IRQ pins connected
+to the INTC block on recent SoCs from Renesas.
+
+The INTC hardware block usually contains a rather wide
+range of features ranging from external IRQ pin handling
+to legacy interrupt controller support. On older SoCs
+the INTC is used as a general purpose interrupt controller
+both for external IRQ pins and on-chip devices.
+
+On more recent ARM based SoCs with Cortex-A9 the main
+interrupt controller is the GIC, but IRQ trigger setup
+still need to happen in the INTC hardware block.
+
+This driver implements the glue code needed to configure
+IRQ trigger and also handle mask/unmask and demux of
+external IRQ pins hooked up from the INTC to the GIC.
+
+Tested on sh73a0 and r8a7779. The hardware varies quite
+a bit with SoC model, for instance register width and
+bitfield widths vary wildly. The driver requires one GIC
+SPI per external IRQ pin to operate. Each driver instance
+will handle up to 8 external IRQ pins.
+
+The SoCs using this driver are currently mainly used
+together with regular platform devices so this driver
+allows configuration via platform data to support things
+like static interrupt base address. DT support will
+be added incrementally in the not so distant future.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+(cherry picked from commit 0ed30c2820e229e0334f20d93ec75ca196a69162)
+
+Conflicts:
+ drivers/irqchip/Kconfig
+ drivers/irqchip/Makefile
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/irqchip/Kconfig | 4
+ drivers/irqchip/Makefile | 2
+ drivers/irqchip/irq-renesas-intc-irqpin.c | 464 ++++++++++++++++++
+ include/linux/platform_data/irq-renesas-intc-irqpin.h | 10
+ 4 files changed, 480 insertions(+)
+ create mode 100644 drivers/irqchip/irq-renesas-intc-irqpin.c
+ create mode 100644 include/linux/platform_data/irq-renesas-intc-irqpin.h
+
+--- a/drivers/irqchip/Kconfig
++++ b/drivers/irqchip/Kconfig
+@@ -1,3 +1,7 @@
+ config IRQCHIP
+ def_bool y
+ depends on OF_IRQ
++
++config RENESAS_INTC_IRQPIN
++ bool
++ select IRQ_DOMAIN
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -1 +1,3 @@
+ obj-$(CONFIG_IRQCHIP) += irqchip.o
++
++obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
+--- /dev/null
++++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
+@@ -0,0 +1,464 @@
++/*
++ * Renesas INTC External IRQ Pin Driver
++ *
++ * Copyright (C) 2013 Magnus Damm
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/irqdomain.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/platform_data/irq-renesas-intc-irqpin.h>
++
++#define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */
++
++#define INTC_IRQPIN_REG_SENSE 0 /* ICRn */
++#define INTC_IRQPIN_REG_PRIO 1 /* INTPRInn */
++#define INTC_IRQPIN_REG_SOURCE 2 /* INTREQnn */
++#define INTC_IRQPIN_REG_MASK 3 /* INTMSKnn */
++#define INTC_IRQPIN_REG_CLEAR 4 /* INTMSKCLRnn */
++#define INTC_IRQPIN_REG_NR 5
++
++/* INTC external IRQ PIN hardware register access:
++ *
++ * SENSE is read-write 32-bit with 2-bits or 4-bits per IRQ (*)
++ * PRIO is read-write 32-bit with 4-bits per IRQ (**)
++ * SOURCE is read-only 32-bit or 8-bit with 1-bit per IRQ (***)
++ * MASK is write-only 32-bit or 8-bit with 1-bit per IRQ (***)
++ * CLEAR is write-only 32-bit or 8-bit with 1-bit per IRQ (***)
++ *
++ * (*) May be accessed by more than one driver instance - lock needed
++ * (**) Read-modify-write access by one driver instance - lock needed
++ * (***) Accessed by one driver instance only - no locking needed
++ */
++
++struct intc_irqpin_iomem {
++ void __iomem *iomem;
++ unsigned long (*read)(void __iomem *iomem);
++ void (*write)(void __iomem *iomem, unsigned long data);
++ int width;
++};
++
++struct intc_irqpin_irq {
++ int hw_irq;
++ int irq;
++ struct intc_irqpin_priv *p;
++};
++
++struct intc_irqpin_priv {
++ struct intc_irqpin_iomem iomem[INTC_IRQPIN_REG_NR];
++ struct intc_irqpin_irq irq[INTC_IRQPIN_MAX];
++ struct renesas_intc_irqpin_config config;
++ unsigned int number_of_irqs;
++ struct platform_device *pdev;
++ struct irq_chip irq_chip;
++ struct irq_domain *irq_domain;
++};
++
++static unsigned long intc_irqpin_read32(void __iomem *iomem)
++{
++ return ioread32(iomem);
++}
++
++static unsigned long intc_irqpin_read8(void __iomem *iomem)
++{
++ return ioread8(iomem);
++}
++
++static void intc_irqpin_write32(void __iomem *iomem, unsigned long data)
++{
++ iowrite32(data, iomem);
++}
++
++static void intc_irqpin_write8(void __iomem *iomem, unsigned long data)
++{
++ iowrite8(data, iomem);
++}
++
++static inline unsigned long intc_irqpin_read(struct intc_irqpin_priv *p,
++ int reg)
++{
++ struct intc_irqpin_iomem *i = &p->iomem[reg];
++ return i->read(i->iomem);
++}
++
++static inline void intc_irqpin_write(struct intc_irqpin_priv *p,
++ int reg, unsigned long data)
++{
++ struct intc_irqpin_iomem *i = &p->iomem[reg];
++ i->write(i->iomem, data);
++}
++
++static inline unsigned long intc_irqpin_hwirq_mask(struct intc_irqpin_priv *p,
++ int reg, int hw_irq)
++{
++ return BIT((p->iomem[reg].width - 1) - hw_irq);
++}
++
++static inline void intc_irqpin_irq_write_hwirq(struct intc_irqpin_priv *p,
++ int reg, int hw_irq)
++{
++ intc_irqpin_write(p, reg, intc_irqpin_hwirq_mask(p, reg, hw_irq));
++}
++
++static DEFINE_RAW_SPINLOCK(intc_irqpin_lock); /* only used by slow path */
++
++static void intc_irqpin_read_modify_write(struct intc_irqpin_priv *p,
++ int reg, int shift,
++ int width, int value)
++{
++ unsigned long flags;
++ unsigned long tmp;
++
++ raw_spin_lock_irqsave(&intc_irqpin_lock, flags);
++
++ tmp = intc_irqpin_read(p, reg);
++ tmp &= ~(((1 << width) - 1) << shift);
++ tmp |= value << shift;
++ intc_irqpin_write(p, reg, tmp);
++
++ raw_spin_unlock_irqrestore(&intc_irqpin_lock, flags);
++}
++
++static void intc_irqpin_mask_unmask_prio(struct intc_irqpin_priv *p,
++ int irq, int do_mask)
++{
++ int bitfield_width = 4; /* PRIO assumed to have fixed bitfield width */
++ int shift = (7 - irq) * bitfield_width; /* PRIO assumed to be 32-bit */
++
++ intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_PRIO,
++ shift, bitfield_width,
++ do_mask ? 0 : (1 << bitfield_width) - 1);
++}
++
++static int intc_irqpin_set_sense(struct intc_irqpin_priv *p, int irq, int value)
++{
++ int bitfield_width = p->config.sense_bitfield_width;
++ int shift = (7 - irq) * bitfield_width; /* SENSE assumed to be 32-bit */
++
++ dev_dbg(&p->pdev->dev, "sense irq = %d, mode = %d\n", irq, value);
++
++ if (value >= (1 << bitfield_width))
++ return -EINVAL;
++
++ intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_SENSE, shift,
++ bitfield_width, value);
++ return 0;
++}
++
++static void intc_irqpin_dbg(struct intc_irqpin_irq *i, char *str)
++{
++ dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)\n",
++ str, i->irq, i->hw_irq,
++ irq_find_mapping(i->p->irq_domain, i->hw_irq));
++}
++
++static void intc_irqpin_irq_enable(struct irq_data *d)
++{
++ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
++ int hw_irq = irqd_to_hwirq(d);
++
++ intc_irqpin_dbg(&p->irq[hw_irq], "enable");
++ intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq);
++}
++
++static void intc_irqpin_irq_disable(struct irq_data *d)
++{
++ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
++ int hw_irq = irqd_to_hwirq(d);
++
++ intc_irqpin_dbg(&p->irq[hw_irq], "disable");
++ intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq);
++}
++
++static void intc_irqpin_irq_enable_force(struct irq_data *d)
++{
++ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
++ int irq = p->irq[irqd_to_hwirq(d)].irq;
++
++ intc_irqpin_irq_enable(d);
++ irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
++}
++
++static void intc_irqpin_irq_disable_force(struct irq_data *d)
++{
++ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
++ int irq = p->irq[irqd_to_hwirq(d)].irq;
++
++ irq_get_chip(irq)->irq_mask(irq_get_irq_data(irq));
++ intc_irqpin_irq_disable(d);
++}
++
++#define INTC_IRQ_SENSE_VALID 0x10
++#define INTC_IRQ_SENSE(x) (x + INTC_IRQ_SENSE_VALID)
++
++static unsigned char intc_irqpin_sense[IRQ_TYPE_SENSE_MASK + 1] = {
++ [IRQ_TYPE_EDGE_FALLING] = INTC_IRQ_SENSE(0x00),
++ [IRQ_TYPE_EDGE_RISING] = INTC_IRQ_SENSE(0x01),
++ [IRQ_TYPE_LEVEL_LOW] = INTC_IRQ_SENSE(0x02),
++ [IRQ_TYPE_LEVEL_HIGH] = INTC_IRQ_SENSE(0x03),
++ [IRQ_TYPE_EDGE_BOTH] = INTC_IRQ_SENSE(0x04),
++};
++
++static int intc_irqpin_irq_set_type(struct irq_data *d, unsigned int type)
++{
++ unsigned char value = intc_irqpin_sense[type & IRQ_TYPE_SENSE_MASK];
++ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
++
++ if (!(value & INTC_IRQ_SENSE_VALID))
++ return -EINVAL;
++
++ return intc_irqpin_set_sense(p, irqd_to_hwirq(d),
++ value ^ INTC_IRQ_SENSE_VALID);
++}
++
++static irqreturn_t intc_irqpin_irq_handler(int irq, void *dev_id)
++{
++ struct intc_irqpin_irq *i = dev_id;
++ struct intc_irqpin_priv *p = i->p;
++ unsigned long bit;
++
++ intc_irqpin_dbg(i, "demux1");
++ bit = intc_irqpin_hwirq_mask(p, INTC_IRQPIN_REG_SOURCE, i->hw_irq);
++
++ if (intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE) & bit) {
++ intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, ~bit);
++ intc_irqpin_dbg(i, "demux2");
++ generic_handle_irq(irq_find_mapping(p->irq_domain, i->hw_irq));
++ return IRQ_HANDLED;
++ }
++ return IRQ_NONE;
++}
++
++static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq,
++ irq_hw_number_t hw)
++{
++ struct intc_irqpin_priv *p = h->host_data;
++
++ intc_irqpin_dbg(&p->irq[hw], "map");
++ irq_set_chip_data(virq, h->host_data);
++ irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
++ set_irq_flags(virq, IRQF_VALID); /* kill me now */
++ return 0;
++}
++
++static struct irq_domain_ops intc_irqpin_irq_domain_ops = {
++ .map = intc_irqpin_irq_domain_map,
++};
++
++static int intc_irqpin_probe(struct platform_device *pdev)
++{
++ struct renesas_intc_irqpin_config *pdata = pdev->dev.platform_data;
++ struct intc_irqpin_priv *p;
++ struct intc_irqpin_iomem *i;
++ struct resource *io[INTC_IRQPIN_REG_NR];
++ struct resource *irq;
++ struct irq_chip *irq_chip;
++ void (*enable_fn)(struct irq_data *d);
++ void (*disable_fn)(struct irq_data *d);
++ const char *name = dev_name(&pdev->dev);
++ int ret;
++ int k;
++
++ p = kzalloc(sizeof(*p), GFP_KERNEL);
++ if (!p) {
++ dev_err(&pdev->dev, "failed to allocate driver data\n");
++ ret = -ENOMEM;
++ goto err0;
++ }
++
++ /* deal with driver instance configuration */
++ if (pdata)
++ memcpy(&p->config, pdata, sizeof(*pdata));
++ if (!p->config.sense_bitfield_width)
++ p->config.sense_bitfield_width = 4; /* default to 4 bits */
++
++ p->pdev = pdev;
++ platform_set_drvdata(pdev, p);
++
++ /* get hold of manadatory IOMEM */
++ for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
++ io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k);
++ if (!io[k]) {
++ dev_err(&pdev->dev, "not enough IOMEM resources\n");
++ ret = -EINVAL;
++ goto err1;
++ }
++ }
++
++ /* allow any number of IRQs between 1 and INTC_IRQPIN_MAX */
++ for (k = 0; k < INTC_IRQPIN_MAX; k++) {
++ irq = platform_get_resource(pdev, IORESOURCE_IRQ, k);
++ if (!irq)
++ break;
++
++ p->irq[k].hw_irq = k;
++ p->irq[k].p = p;
++ p->irq[k].irq = irq->start;
++ }
++
++ p->number_of_irqs = k;
++ if (p->number_of_irqs < 1) {
++ dev_err(&pdev->dev, "not enough IRQ resources\n");
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* ioremap IOMEM and setup read/write callbacks */
++ for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
++ i = &p->iomem[k];
++
++ switch (resource_size(io[k])) {
++ case 1:
++ i->width = 8;
++ i->read = intc_irqpin_read8;
++ i->write = intc_irqpin_write8;
++ break;
++ case 4:
++ i->width = 32;
++ i->read = intc_irqpin_read32;
++ i->write = intc_irqpin_write32;
++ break;
++ default:
++ dev_err(&pdev->dev, "IOMEM size mismatch\n");
++ ret = -EINVAL;
++ goto err2;
++ }
++
++ i->iomem = ioremap_nocache(io[k]->start, resource_size(io[k]));
++ if (!i->iomem) {
++ dev_err(&pdev->dev, "failed to remap IOMEM\n");
++ ret = -ENXIO;
++ goto err2;
++ }
++ }
++
++ /* mask all interrupts using priority */
++ for (k = 0; k < p->number_of_irqs; k++)
++ intc_irqpin_mask_unmask_prio(p, k, 1);
++
++ /* use more severe masking method if requested */
++ if (p->config.control_parent) {
++ enable_fn = intc_irqpin_irq_enable_force;
++ disable_fn = intc_irqpin_irq_disable_force;
++ } else {
++ enable_fn = intc_irqpin_irq_enable;
++ disable_fn = intc_irqpin_irq_disable;
++ }
++
++ irq_chip = &p->irq_chip;
++ irq_chip->name = name;
++ irq_chip->irq_mask = disable_fn;
++ irq_chip->irq_unmask = enable_fn;
++ irq_chip->irq_enable = enable_fn;
++ irq_chip->irq_disable = disable_fn;
++ irq_chip->irq_set_type = intc_irqpin_irq_set_type;
++ irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
++
++ p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
++ p->number_of_irqs,
++ p->config.irq_base,
++ &intc_irqpin_irq_domain_ops, p);
++ if (!p->irq_domain) {
++ ret = -ENXIO;
++ dev_err(&pdev->dev, "cannot initialize irq domain\n");
++ goto err2;
++ }
++
++ /* request and set priority on interrupts one by one */
++ for (k = 0; k < p->number_of_irqs; k++) {
++ if (request_irq(p->irq[k].irq, intc_irqpin_irq_handler,
++ 0, name, &p->irq[k])) {
++ dev_err(&pdev->dev, "failed to request low IRQ\n");
++ ret = -ENOENT;
++ goto err3;
++ }
++ intc_irqpin_mask_unmask_prio(p, k, 0);
++ }
++
++ dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs);
++
++ /* warn in case of mismatch if irq base is specified */
++ if (p->config.irq_base) {
++ k = irq_find_mapping(p->irq_domain, 0);
++ if (p->config.irq_base != k)
++ dev_warn(&pdev->dev, "irq base mismatch (%d/%d)\n",
++ p->config.irq_base, k);
++ }
++
++ return 0;
++
++err3:
++ for (; k >= 0; k--)
++ free_irq(p->irq[k - 1].irq, &p->irq[k - 1]);
++
++ irq_domain_remove(p->irq_domain);
++err2:
++ for (k = 0; k < INTC_IRQPIN_REG_NR; k++)
++ iounmap(p->iomem[k].iomem);
++err1:
++ kfree(p);
++err0:
++ return ret;
++}
++
++static int intc_irqpin_remove(struct platform_device *pdev)
++{
++ struct intc_irqpin_priv *p = platform_get_drvdata(pdev);
++ int k;
++
++ for (k = 0; k < p->number_of_irqs; k++)
++ free_irq(p->irq[k].irq, &p->irq[k]);
++
++ irq_domain_remove(p->irq_domain);
++
++ for (k = 0; k < INTC_IRQPIN_REG_NR; k++)
++ iounmap(p->iomem[k].iomem);
++
++ kfree(p);
++ return 0;
++}
++
++static struct platform_driver intc_irqpin_device_driver = {
++ .probe = intc_irqpin_probe,
++ .remove = intc_irqpin_remove,
++ .driver = {
++ .name = "renesas_intc_irqpin",
++ }
++};
++
++static int __init intc_irqpin_init(void)
++{
++ return platform_driver_register(&intc_irqpin_device_driver);
++}
++postcore_initcall(intc_irqpin_init);
++
++static void __exit intc_irqpin_exit(void)
++{
++ platform_driver_unregister(&intc_irqpin_device_driver);
++}
++module_exit(intc_irqpin_exit);
++
++MODULE_AUTHOR("Magnus Damm");
++MODULE_DESCRIPTION("Renesas INTC External IRQ Pin Driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/include/linux/platform_data/irq-renesas-intc-irqpin.h
+@@ -0,0 +1,10 @@
++#ifndef __IRQ_RENESAS_INTC_IRQPIN_H__
++#define __IRQ_RENESAS_INTC_IRQPIN_H__
++
++struct renesas_intc_irqpin_config {
++ unsigned int sense_bitfield_width;
++ unsigned int irq_base;
++ bool control_parent;
++};
++
++#endif /* __IRQ_RENESAS_INTC_IRQPIN_H__ */
diff --git a/patches.misc/0005-irqchip-intc-irqpin-Cache-mapped-IRQ.patch b/patches.misc/0005-irqchip-intc-irqpin-Cache-mapped-IRQ.patch
new file mode 100644
index 00000000000..43e41c66aca
--- /dev/null
+++ b/patches.misc/0005-irqchip-intc-irqpin-Cache-mapped-IRQ.patch
@@ -0,0 +1,128 @@
+From 12395af649b20eb8a23d1e69b2ba8aa6ba6ae8f9 Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Tue, 26 Feb 2013 20:58:54 +0900
+Subject: irqchip: intc-irqpin: Cache mapped IRQ
+
+Cache IRQ in domain_irq variable instead of
+making use of irq_find_mapping(). While at it
+rename the irq variable to requested_irq.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+(cherry picked from commit 325a9c2426dd7144fc3d56397286ce1e69713c12)
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/irqchip/irq-renesas-intc-irqpin.c | 30 ++++++++++++++++--------------
+ 1 file changed, 16 insertions(+), 14 deletions(-)
+
+--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
++++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
+@@ -61,7 +61,8 @@ struct intc_irqpin_iomem {
+
+ struct intc_irqpin_irq {
+ int hw_irq;
+- int irq;
++ int requested_irq;
++ int domain_irq;
+ struct intc_irqpin_priv *p;
+ };
+
+@@ -169,8 +170,7 @@ static int intc_irqpin_set_sense(struct
+ static void intc_irqpin_dbg(struct intc_irqpin_irq *i, char *str)
+ {
+ dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)\n",
+- str, i->irq, i->hw_irq,
+- irq_find_mapping(i->p->irq_domain, i->hw_irq));
++ str, i->requested_irq, i->hw_irq, i->domain_irq);
+ }
+
+ static void intc_irqpin_irq_enable(struct irq_data *d)
+@@ -194,7 +194,7 @@ static void intc_irqpin_irq_disable(stru
+ static void intc_irqpin_irq_enable_force(struct irq_data *d)
+ {
+ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
+- int irq = p->irq[irqd_to_hwirq(d)].irq;
++ int irq = p->irq[irqd_to_hwirq(d)].requested_irq;
+
+ intc_irqpin_irq_enable(d);
+ irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
+@@ -203,7 +203,7 @@ static void intc_irqpin_irq_enable_force
+ static void intc_irqpin_irq_disable_force(struct irq_data *d)
+ {
+ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
+- int irq = p->irq[irqd_to_hwirq(d)].irq;
++ int irq = p->irq[irqd_to_hwirq(d)].requested_irq;
+
+ irq_get_chip(irq)->irq_mask(irq_get_irq_data(irq));
+ intc_irqpin_irq_disable(d);
+@@ -244,7 +244,7 @@ static irqreturn_t intc_irqpin_irq_handl
+ if (intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE) & bit) {
+ intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, ~bit);
+ intc_irqpin_dbg(i, "demux2");
+- generic_handle_irq(irq_find_mapping(p->irq_domain, i->hw_irq));
++ generic_handle_irq(i->domain_irq);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+@@ -255,6 +255,9 @@ static int intc_irqpin_irq_domain_map(st
+ {
+ struct intc_irqpin_priv *p = h->host_data;
+
++ p->irq[hw].domain_irq = virq;
++ p->irq[hw].hw_irq = hw;
++
+ intc_irqpin_dbg(&p->irq[hw], "map");
+ irq_set_chip_data(virq, h->host_data);
+ irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
+@@ -312,9 +315,8 @@ static int intc_irqpin_probe(struct plat
+ if (!irq)
+ break;
+
+- p->irq[k].hw_irq = k;
+ p->irq[k].p = p;
+- p->irq[k].irq = irq->start;
++ p->irq[k].requested_irq = irq->start;
+ }
+
+ p->number_of_irqs = k;
+@@ -387,7 +389,8 @@ static int intc_irqpin_probe(struct plat
+
+ /* request and set priority on interrupts one by one */
+ for (k = 0; k < p->number_of_irqs; k++) {
+- if (request_irq(p->irq[k].irq, intc_irqpin_irq_handler,
++ if (request_irq(p->irq[k].requested_irq,
++ intc_irqpin_irq_handler,
+ 0, name, &p->irq[k])) {
+ dev_err(&pdev->dev, "failed to request low IRQ\n");
+ ret = -ENOENT;
+@@ -400,17 +403,16 @@ static int intc_irqpin_probe(struct plat
+
+ /* warn in case of mismatch if irq base is specified */
+ if (p->config.irq_base) {
+- k = irq_find_mapping(p->irq_domain, 0);
+- if (p->config.irq_base != k)
++ if (p->config.irq_base != p->irq[0].domain_irq)
+ dev_warn(&pdev->dev, "irq base mismatch (%d/%d)\n",
+- p->config.irq_base, k);
++ p->config.irq_base, p->irq[0].domain_irq);
+ }
+
+ return 0;
+
+ err3:
+ for (; k >= 0; k--)
+- free_irq(p->irq[k - 1].irq, &p->irq[k - 1]);
++ free_irq(p->irq[k - 1].requested_irq, &p->irq[k - 1]);
+
+ irq_domain_remove(p->irq_domain);
+ err2:
+@@ -428,7 +430,7 @@ static int intc_irqpin_remove(struct pla
+ int k;
+
+ for (k = 0; k < p->number_of_irqs; k++)
+- free_irq(p->irq[k].irq, &p->irq[k]);
++ free_irq(p->irq[k].requested_irq, &p->irq[k]);
+
+ irq_domain_remove(p->irq_domain);
+
diff --git a/patches.misc/0006-ARM-shmobile-irq_pin-for-static-IRQ-pin-assignment.patch b/patches.misc/0006-ARM-shmobile-irq_pin-for-static-IRQ-pin-assignment.patch
new file mode 100644
index 00000000000..d009d3067b5
--- /dev/null
+++ b/patches.misc/0006-ARM-shmobile-irq_pin-for-static-IRQ-pin-assignment.patch
@@ -0,0 +1,28 @@
+From d0f1eb80c491e8e0d13f6c413cf16f1f6cc609a0 Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Tue, 26 Feb 2013 12:00:59 +0900
+Subject: ARM: shmobile: irq_pin() for static IRQ pin assignment
+
+Add the macro irq_pin() to let board-specific code using
+platform devices tie in external IRQn pins in a common way.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+(cherry picked from commit a877feb63cb49b7fa4722f9a0e61949bd46d4577)
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ arch/arm/mach-shmobile/include/mach/irqs.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm/mach-shmobile/include/mach/irqs.h
++++ b/arch/arm/mach-shmobile/include/mach/irqs.h
+@@ -11,4 +11,8 @@
+ #define INTCS_VECT(n, vect) INTC_VECT((n), INTCS_VECT_BASE + (vect))
+ #define intcs_evt2irq(evt) evt2irq(INTCS_VECT_BASE + (evt))
+
++/* External IRQ pins */
++#define IRQPIN_BASE 2000
++#define irq_pin(nr) ((nr) + IRQPIN_BASE)
++
+ #endif /* __ASM_MACH_IRQS_H */
diff --git a/patches.misc/0007-ARM-shmobile-INTC-External-IRQ-pin-driver-on-r8a7779.patch b/patches.misc/0007-ARM-shmobile-INTC-External-IRQ-pin-driver-on-r8a7779.patch
new file mode 100644
index 00000000000..a2e29213539
--- /dev/null
+++ b/patches.misc/0007-ARM-shmobile-INTC-External-IRQ-pin-driver-on-r8a7779.patch
@@ -0,0 +1,155 @@
+From 25598603d52c830b2c317ab1b94155525b11c09c Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Tue, 26 Feb 2013 12:01:18 +0900
+Subject: ARM: shmobile: INTC External IRQ pin driver on r8a7779
+
+Update the r8a7779 IRQ code to make use of the
+INTC External IRQ pin driver for external
+interrupt pins IRQ0 -> IRQ3.
+
+The r8a7779 SoC can like older SH SoCs configure
+to use the IRQ0 -> IRQ3 signals as individual
+interrupts or a combined IRL mode.
+
+Without this patch the r8a7779 SoC code does
+not fully support external IRQ pins in individual
+IRQ mode. The r8a7779 PFC code does not yet have
+gpio_to_irq() support so no need to update such
+code.
+
+At this point the DT reference implementations
+are not covered. In the future such code shall
+tie in the INTC External IRQ pin driver via
+DT, so this kind of verbose code is not needed
+for the long term DT case.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+(cherry picked from commit dd9e1fa565b335a5fd2768b772c673a4860196d7)
+
+Conflicts:
+ arch/arm/mach-shmobile/Kconfig
+ arch/arm/mach-shmobile/include/mach/common.h
+ arch/arm/mach-shmobile/intc-r8a7779.c
+
+Signed-off-by: Simon Horman <horms@verge.net.au>
+---
+ arch/arm/mach-shmobile/Kconfig | 1
+ arch/arm/mach-shmobile/board-marzen.c | 3 +
+ arch/arm/mach-shmobile/include/mach/common.h | 2 +
+ arch/arm/mach-shmobile/intc-r8a7779.c | 52 +++++++++++++++++++++++++++
+ 4 files changed, 57 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/mach-shmobile/Kconfig
++++ b/arch/arm/mach-shmobile/Kconfig
+@@ -40,6 +40,7 @@ config ARCH_R8A7779
+ select SH_CLK_CPG
+ select ARM_GIC
+ select ARCH_WANT_OPTIONAL_GPIOLIB
++ select RENESAS_INTC_IRQPIN
+
+ config ARCH_EMEV2
+ bool "Emma Mobile EV2"
+--- a/arch/arm/mach-shmobile/board-marzen.c
++++ b/arch/arm/mach-shmobile/board-marzen.c
+@@ -53,7 +53,7 @@ static struct resource smsc911x_resource
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = gic_spi(28), /* IRQ 1 */
++ .start = irq_pin(1), /* IRQ1 */
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -84,6 +84,7 @@ static void __init marzen_init(void)
+ regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
+ r8a7779_pinmux_init();
++ r8a7779_init_irq_extpin(1); /* IRQ1 as individual interrupt */
+
+ /* SCIF2 (CN18: DEBUG0) */
+ gpio_request(GPIO_FN_TX2_C, NULL);
+--- a/arch/arm/mach-shmobile/include/mach/common.h
++++ b/arch/arm/mach-shmobile/include/mach/common.h
+@@ -66,6 +66,8 @@ extern void r8a7740_reserve_memory(void)
+ extern void r8a7740_pinmux_init(void);
+
+ extern void r8a7779_init_irq(void);
++extern void r8a7779_init_irq_extpin(int irlm);
++extern void r8a7779_init_irq_dt(void);
+ extern void r8a7779_map_io(void);
+ extern void r8a7779_add_early_devices(void);
+ extern void r8a7779_add_standard_devices(void);
+--- a/arch/arm/mach-shmobile/intc-r8a7779.c
++++ b/arch/arm/mach-shmobile/intc-r8a7779.c
+@@ -19,11 +19,15 @@
+ */
+ #include <linux/kernel.h>
+ #include <linux/init.h>
++#include <linux/platform_device.h>
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
+ #include <linux/io.h>
++#include <linux/platform_data/irq-renesas-intc-irqpin.h>
++#include <linux/irqchip.h>
+ #include <mach/common.h>
+ #include <mach/intc.h>
++#include <mach/irqs.h>
+ #include <mach/r8a7779.h>
+ #include <asm/hardware/gic.h>
+ #include <asm/mach-types.h>
+@@ -38,6 +42,54 @@
+ #define INT2NTSR0 0xfe700060
+ #define INT2NTSR1 0xfe700064
+
++struct renesas_intc_irqpin_config irqpin0_platform_data = {
++ .irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */
++ .sense_bitfield_width = 2,
++};
++
++static struct resource irqpin0_resources[] = {
++ DEFINE_RES_MEM(0xfe78001c, 4), /* ICR1 */
++ DEFINE_RES_MEM(0xfe780010, 4), /* INTPRI */
++ DEFINE_RES_MEM(0xfe780024, 4), /* INTREQ */
++ DEFINE_RES_MEM(0xfe780044, 4), /* INTMSK0 */
++ DEFINE_RES_MEM(0xfe780064, 4), /* INTMSKCLR0 */
++ DEFINE_RES_IRQ(gic_spi(27)), /* IRQ0 */
++ DEFINE_RES_IRQ(gic_spi(28)), /* IRQ1 */
++ DEFINE_RES_IRQ(gic_spi(29)), /* IRQ2 */
++ DEFINE_RES_IRQ(gic_spi(30)), /* IRQ3 */
++};
++
++static struct platform_device irqpin0_device = {
++ .name = "renesas_intc_irqpin",
++ .id = 0,
++ .resource = irqpin0_resources,
++ .num_resources = ARRAY_SIZE(irqpin0_resources),
++ .dev = {
++ .platform_data = &irqpin0_platform_data,
++ },
++};
++
++void __init r8a7779_init_irq_extpin(int irlm)
++{
++ void __iomem *icr0 = ioremap_nocache(0xfe780000, PAGE_SIZE);
++ unsigned long tmp;
++
++ if (icr0) {
++ tmp = ioread32(icr0);
++ if (irlm)
++ tmp |= 1 << 23; /* IRQ0 -> IRQ3 as individual pins */
++ else
++ tmp &= ~(1 << 23); /* IRL mode - not supported */
++ tmp |= (1 << 21); /* LVLMODE = 1 */
++ iowrite32(tmp, icr0);
++ iounmap(icr0);
++
++ if (irlm)
++ platform_device_register(&irqpin0_device);
++ } else
++ pr_warn("r8a7779: unable to setup external irq pin mode\n");
++}
++
+ static int r8a7779_set_wake(struct irq_data *data, unsigned int on)
+ {
+ return 0; /* always allow wakeup */
diff --git a/patches.misc/0008-irqchip-intc-irqpin-Whitespace-fixes.patch b/patches.misc/0008-irqchip-intc-irqpin-Whitespace-fixes.patch
new file mode 100644
index 00000000000..b6d5088a59c
--- /dev/null
+++ b/patches.misc/0008-irqchip-intc-irqpin-Whitespace-fixes.patch
@@ -0,0 +1,34 @@
+From fe6c5fcec31e66f5b03f0380c0644bb7a1637ea4 Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Tue, 26 Feb 2013 20:58:44 +0900
+Subject: irqchip: intc-irqpin: Whitespace fixes
+
+Remove whitespace damage and add newline
+between variables and code.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/irqchip/irq-renesas-intc-irqpin.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
++++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
+@@ -100,6 +100,7 @@ static inline unsigned long intc_irqpin_
+ int reg)
+ {
+ struct intc_irqpin_iomem *i = &p->iomem[reg];
++
+ return i->read(i->iomem);
+ }
+
+@@ -107,6 +108,7 @@ static inline void intc_irqpin_write(str
+ int reg, unsigned long data)
+ {
+ struct intc_irqpin_iomem *i = &p->iomem[reg];
++
+ i->write(i->iomem, data);
+ }
+
diff --git a/patches.misc/0009-irqchip-intc-irqpin-Add-force-comments.patch b/patches.misc/0009-irqchip-intc-irqpin-Add-force-comments.patch
new file mode 100644
index 00000000000..b8d0e622b88
--- /dev/null
+++ b/patches.misc/0009-irqchip-intc-irqpin-Add-force-comments.patch
@@ -0,0 +1,41 @@
+From b0791671eb6cc3c794f3649dd37dfbd88980e355 Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Tue, 26 Feb 2013 20:59:04 +0900
+Subject: irqchip: intc-irqpin: Add force comments
+
+Add comments to describe the special case for
+"force" versions of enable and disable functions.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/irqchip/irq-renesas-intc-irqpin.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
++++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
+@@ -199,6 +199,11 @@ static void intc_irqpin_irq_enable_force
+ int irq = p->irq[irqd_to_hwirq(d)].requested_irq;
+
+ intc_irqpin_irq_enable(d);
++
++ /* enable interrupt through parent interrupt controller,
++ * assumes non-shared interrupt with 1:1 mapping
++ * needed for busted IRQs on some SoCs like sh73a0
++ */
+ irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
+ }
+
+@@ -207,6 +212,10 @@ static void intc_irqpin_irq_disable_forc
+ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
+ int irq = p->irq[irqd_to_hwirq(d)].requested_irq;
+
++ /* disable interrupt through parent interrupt controller,
++ * assumes non-shared interrupt with 1:1 mapping
++ * needed for busted IRQs on some SoCs like sh73a0
++ */
+ irq_get_chip(irq)->irq_mask(irq_get_irq_data(irq));
+ intc_irqpin_irq_disable(d);
+ }
diff --git a/patches.misc/0010-irqchip-intc-irqpin-Make-use-of-devm-functions.patch b/patches.misc/0010-irqchip-intc-irqpin-Make-use-of-devm-functions.patch
new file mode 100644
index 00000000000..b408f157087
--- /dev/null
+++ b/patches.misc/0010-irqchip-intc-irqpin-Make-use-of-devm-functions.patch
@@ -0,0 +1,124 @@
+From e89972262ef0aa2b47a1be58aa72fb6d17c4125e Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Tue, 26 Feb 2013 20:59:13 +0900
+Subject: irqchip: intc-irqpin: Make use of devm functions
+
+Use devm_kzalloc(), devm_ioremap_nocache()
+and devm_request_irq() to simplify error
+handling.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/irqchip/irq-renesas-intc-irqpin.c | 41 +++++++++---------------------
+ 1 file changed, 13 insertions(+), 28 deletions(-)
+
+--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
++++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
+@@ -294,7 +294,7 @@ static int intc_irqpin_probe(struct plat
+ int ret;
+ int k;
+
+- p = kzalloc(sizeof(*p), GFP_KERNEL);
++ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ dev_err(&pdev->dev, "failed to allocate driver data\n");
+ ret = -ENOMEM;
+@@ -316,7 +316,7 @@ static int intc_irqpin_probe(struct plat
+ if (!io[k]) {
+ dev_err(&pdev->dev, "not enough IOMEM resources\n");
+ ret = -EINVAL;
+- goto err1;
++ goto err0;
+ }
+ }
+
+@@ -334,7 +334,7 @@ static int intc_irqpin_probe(struct plat
+ if (p->number_of_irqs < 1) {
+ dev_err(&pdev->dev, "not enough IRQ resources\n");
+ ret = -EINVAL;
+- goto err1;
++ goto err0;
+ }
+
+ /* ioremap IOMEM and setup read/write callbacks */
+@@ -355,14 +355,15 @@ static int intc_irqpin_probe(struct plat
+ default:
+ dev_err(&pdev->dev, "IOMEM size mismatch\n");
+ ret = -EINVAL;
+- goto err2;
++ goto err0;
+ }
+
+- i->iomem = ioremap_nocache(io[k]->start, resource_size(io[k]));
++ i->iomem = devm_ioremap_nocache(&pdev->dev, io[k]->start,
++ resource_size(io[k]));
+ if (!i->iomem) {
+ dev_err(&pdev->dev, "failed to remap IOMEM\n");
+ ret = -ENXIO;
+- goto err2;
++ goto err0;
+ }
+ }
+
+@@ -395,17 +396,17 @@ static int intc_irqpin_probe(struct plat
+ if (!p->irq_domain) {
+ ret = -ENXIO;
+ dev_err(&pdev->dev, "cannot initialize irq domain\n");
+- goto err2;
++ goto err0;
+ }
+
+ /* request and set priority on interrupts one by one */
+ for (k = 0; k < p->number_of_irqs; k++) {
+- if (request_irq(p->irq[k].requested_irq,
+- intc_irqpin_irq_handler,
+- 0, name, &p->irq[k])) {
++ if (devm_request_irq(&pdev->dev, p->irq[k].requested_irq,
++ intc_irqpin_irq_handler,
++ 0, name, &p->irq[k])) {
+ dev_err(&pdev->dev, "failed to request low IRQ\n");
+ ret = -ENOENT;
+- goto err3;
++ goto err1;
+ }
+ intc_irqpin_mask_unmask_prio(p, k, 0);
+ }
+@@ -421,16 +422,8 @@ static int intc_irqpin_probe(struct plat
+
+ return 0;
+
+-err3:
+- for (; k >= 0; k--)
+- free_irq(p->irq[k - 1].requested_irq, &p->irq[k - 1]);
+-
+- irq_domain_remove(p->irq_domain);
+-err2:
+- for (k = 0; k < INTC_IRQPIN_REG_NR; k++)
+- iounmap(p->iomem[k].iomem);
+ err1:
+- kfree(p);
++ irq_domain_remove(p->irq_domain);
+ err0:
+ return ret;
+ }
+@@ -438,17 +431,9 @@ err0:
+ static int intc_irqpin_remove(struct platform_device *pdev)
+ {
+ struct intc_irqpin_priv *p = platform_get_drvdata(pdev);
+- int k;
+-
+- for (k = 0; k < p->number_of_irqs; k++)
+- free_irq(p->irq[k].requested_irq, &p->irq[k]);
+
+ irq_domain_remove(p->irq_domain);
+
+- for (k = 0; k < INTC_IRQPIN_REG_NR; k++)
+- iounmap(p->iomem[k].iomem);
+-
+- kfree(p);
+ return 0;
+ }
+
diff --git a/patches.misc/0011-irqchip-intc-irqpin-GPL-header-for-platform-data.patch b/patches.misc/0011-irqchip-intc-irqpin-GPL-header-for-platform-data.patch
new file mode 100644
index 00000000000..06aeaa838b7
--- /dev/null
+++ b/patches.misc/0011-irqchip-intc-irqpin-GPL-header-for-platform-data.patch
@@ -0,0 +1,40 @@
+From 8143994e7681c68def57a0b57bfd8c789912eca1 Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Tue, 26 Feb 2013 20:59:23 +0900
+Subject: irqchip: intc-irqpin: GPL header for platform data
+
+Add GPL header to platform data include file.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ include/linux/platform_data/irq-renesas-intc-irqpin.h | 19 ++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+--- a/include/linux/platform_data/irq-renesas-intc-irqpin.h
++++ b/include/linux/platform_data/irq-renesas-intc-irqpin.h
+@@ -1,3 +1,22 @@
++/*
++ * Renesas INTC External IRQ Pin Driver
++ *
++ * Copyright (C) 2013 Magnus Damm
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
+ #ifndef __IRQ_RENESAS_INTC_IRQPIN_H__
+ #define __IRQ_RENESAS_INTC_IRQPIN_H__
+
diff --git a/patches.misc/0012-irqchip-Renesas-IRQC-driver.patch b/patches.misc/0012-irqchip-Renesas-IRQC-driver.patch
new file mode 100644
index 00000000000..01a17c6d734
--- /dev/null
+++ b/patches.misc/0012-irqchip-Renesas-IRQC-driver.patch
@@ -0,0 +1,395 @@
+From ce9327175f66480b635210af8c2b38a7780fc573 Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Wed, 27 Feb 2013 17:15:01 +0900
+Subject: irqchip: Renesas IRQC driver
+
+This patch adds a driver for external IRQ pins connected
+to the IRQC hardware block on recent SoCs from Renesas.
+
+The IRQC hardware block is used together with more
+recent ARM based SoCs using the GIC. As usual the GIC
+requires external IRQ trigger setup somewhere else
+which in this particular case happens to be IRQC.
+
+This driver implements the glue code needed to configure
+IRQ trigger and also handle mask/unmask and demux of
+external IRQ pins hooked up from the IRQC to the GIC.
+
+Tested on r8a73a4 but is designed to work with a wide
+range of SoCs. The driver requires one GIC SPI per
+external IRQ pin to operate. Each driver instance
+will handle up to 32 external IRQ pins.
+
+The SoCs using this driver are currently mainly used
+together with regular platform devices so this driver
+allows configuration via platform data to support things
+like static interrupt base address. DT support will
+be added incrementally in the not so distant future.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Tested-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+(cherry picked from commit beda1f77bba50a4c78ce17bbcec3a0fdab454e88)
+
+Conflicts:
+ drivers/irqchip/Kconfig
+ drivers/irqchip/Makefile
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/irqchip/Kconfig | 4
+ drivers/irqchip/Makefile | 1
+ drivers/irqchip/irq-renesas-irqc.c | 298 +++++++++++++++++++++++++
+ include/linux/platform_data/irq-renesas-irqc.h | 27 ++
+ 4 files changed, 330 insertions(+)
+ create mode 100644 drivers/irqchip/irq-renesas-irqc.c
+ create mode 100644 include/linux/platform_data/irq-renesas-irqc.h
+
+--- a/drivers/irqchip/Kconfig
++++ b/drivers/irqchip/Kconfig
+@@ -5,3 +5,7 @@ config IRQCHIP
+ config RENESAS_INTC_IRQPIN
+ bool
+ select IRQ_DOMAIN
++
++config RENESAS_IRQC
++ bool
++ select IRQ_DOMAIN
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -1,3 +1,4 @@
+ obj-$(CONFIG_IRQCHIP) += irqchip.o
+
+ obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
++obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o
+--- /dev/null
++++ b/drivers/irqchip/irq-renesas-irqc.c
+@@ -0,0 +1,298 @@
++/*
++ * Renesas IRQC Driver
++ *
++ * Copyright (C) 2013 Magnus Damm
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/irqdomain.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/platform_data/irq-renesas-irqc.h>
++
++#define IRQC_IRQ_MAX 32 /* maximum 32 interrupts per driver instance */
++
++#define IRQC_REQ_STS 0x00
++#define IRQC_EN_STS 0x04
++#define IRQC_EN_SET 0x08
++#define IRQC_INT_CPU_BASE(n) (0x000 + ((n) * 0x10))
++#define DETECT_STATUS 0x100
++#define IRQC_CONFIG(n) (0x180 + ((n) * 0x04))
++
++struct irqc_irq {
++ int hw_irq;
++ int requested_irq;
++ int domain_irq;
++ struct irqc_priv *p;
++};
++
++struct irqc_priv {
++ void __iomem *iomem;
++ void __iomem *cpu_int_base;
++ struct irqc_irq irq[IRQC_IRQ_MAX];
++ struct renesas_irqc_config config;
++ unsigned int number_of_irqs;
++ struct platform_device *pdev;
++ struct irq_chip irq_chip;
++ struct irq_domain *irq_domain;
++};
++
++static void irqc_dbg(struct irqc_irq *i, char *str)
++{
++ dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)\n",
++ str, i->requested_irq, i->hw_irq, i->domain_irq);
++}
++
++static void irqc_irq_enable(struct irq_data *d)
++{
++ struct irqc_priv *p = irq_data_get_irq_chip_data(d);
++ int hw_irq = irqd_to_hwirq(d);
++
++ irqc_dbg(&p->irq[hw_irq], "enable");
++ iowrite32(BIT(hw_irq), p->cpu_int_base + IRQC_EN_SET);
++}
++
++static void irqc_irq_disable(struct irq_data *d)
++{
++ struct irqc_priv *p = irq_data_get_irq_chip_data(d);
++ int hw_irq = irqd_to_hwirq(d);
++
++ irqc_dbg(&p->irq[hw_irq], "disable");
++ iowrite32(BIT(hw_irq), p->cpu_int_base + IRQC_EN_STS);
++}
++
++#define INTC_IRQ_SENSE_VALID 0x10
++#define INTC_IRQ_SENSE(x) (x + INTC_IRQ_SENSE_VALID)
++
++static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = {
++ [IRQ_TYPE_LEVEL_LOW] = INTC_IRQ_SENSE(0x01),
++ [IRQ_TYPE_LEVEL_HIGH] = INTC_IRQ_SENSE(0x02),
++ [IRQ_TYPE_EDGE_FALLING] = INTC_IRQ_SENSE(0x04), /* Synchronous */
++ [IRQ_TYPE_EDGE_RISING] = INTC_IRQ_SENSE(0x08), /* Synchronous */
++ [IRQ_TYPE_EDGE_BOTH] = INTC_IRQ_SENSE(0x0c), /* Synchronous */
++};
++
++static int irqc_irq_set_type(struct irq_data *d, unsigned int type)
++{
++ struct irqc_priv *p = irq_data_get_irq_chip_data(d);
++ int hw_irq = irqd_to_hwirq(d);
++ unsigned char value = irqc_sense[type & IRQ_TYPE_SENSE_MASK];
++ unsigned long tmp;
++
++ irqc_dbg(&p->irq[hw_irq], "sense");
++
++ if (!(value & INTC_IRQ_SENSE_VALID))
++ return -EINVAL;
++
++ tmp = ioread32(p->iomem + IRQC_CONFIG(hw_irq));
++ tmp &= ~0x3f;
++ tmp |= value ^ INTC_IRQ_SENSE_VALID;
++ iowrite32(tmp, p->iomem + IRQC_CONFIG(hw_irq));
++ return 0;
++}
++
++static irqreturn_t irqc_irq_handler(int irq, void *dev_id)
++{
++ struct irqc_irq *i = dev_id;
++ struct irqc_priv *p = i->p;
++ unsigned long bit = BIT(i->hw_irq);
++
++ irqc_dbg(i, "demux1");
++
++ if (ioread32(p->iomem + DETECT_STATUS) & bit) {
++ iowrite32(bit, p->iomem + DETECT_STATUS);
++ irqc_dbg(i, "demux2");
++ generic_handle_irq(i->domain_irq);
++ return IRQ_HANDLED;
++ }
++ return IRQ_NONE;
++}
++
++static int irqc_irq_domain_map(struct irq_domain *h, unsigned int virq,
++ irq_hw_number_t hw)
++{
++ struct irqc_priv *p = h->host_data;
++
++ p->irq[hw].domain_irq = virq;
++ p->irq[hw].hw_irq = hw;
++
++ irqc_dbg(&p->irq[hw], "map");
++ irq_set_chip_data(virq, h->host_data);
++ irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
++ set_irq_flags(virq, IRQF_VALID); /* kill me now */
++ return 0;
++}
++
++static struct irq_domain_ops irqc_irq_domain_ops = {
++ .map = irqc_irq_domain_map,
++};
++
++static int irqc_probe(struct platform_device *pdev)
++{
++ struct renesas_irqc_config *pdata = pdev->dev.platform_data;
++ struct irqc_priv *p;
++ struct resource *io;
++ struct resource *irq;
++ struct irq_chip *irq_chip;
++ const char *name = dev_name(&pdev->dev);
++ int ret;
++ int k;
++
++ p = kzalloc(sizeof(*p), GFP_KERNEL);
++ if (!p) {
++ dev_err(&pdev->dev, "failed to allocate driver data\n");
++ ret = -ENOMEM;
++ goto err0;
++ }
++
++ /* deal with driver instance configuration */
++ if (pdata)
++ memcpy(&p->config, pdata, sizeof(*pdata));
++
++ p->pdev = pdev;
++ platform_set_drvdata(pdev, p);
++
++ /* get hold of manadatory IOMEM */
++ io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!io) {
++ dev_err(&pdev->dev, "not enough IOMEM resources\n");
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* allow any number of IRQs between 1 and IRQC_IRQ_MAX */
++ for (k = 0; k < IRQC_IRQ_MAX; k++) {
++ irq = platform_get_resource(pdev, IORESOURCE_IRQ, k);
++ if (!irq)
++ break;
++
++ p->irq[k].p = p;
++ p->irq[k].requested_irq = irq->start;
++ }
++
++ p->number_of_irqs = k;
++ if (p->number_of_irqs < 1) {
++ dev_err(&pdev->dev, "not enough IRQ resources\n");
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* ioremap IOMEM and setup read/write callbacks */
++ p->iomem = ioremap_nocache(io->start, resource_size(io));
++ if (!p->iomem) {
++ dev_err(&pdev->dev, "failed to remap IOMEM\n");
++ ret = -ENXIO;
++ goto err2;
++ }
++
++ p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */
++
++ irq_chip = &p->irq_chip;
++ irq_chip->name = name;
++ irq_chip->irq_mask = irqc_irq_disable;
++ irq_chip->irq_unmask = irqc_irq_enable;
++ irq_chip->irq_enable = irqc_irq_enable;
++ irq_chip->irq_disable = irqc_irq_disable;
++ irq_chip->irq_set_type = irqc_irq_set_type;
++ irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
++
++ p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
++ p->number_of_irqs,
++ p->config.irq_base,
++ &irqc_irq_domain_ops, p);
++ if (!p->irq_domain) {
++ ret = -ENXIO;
++ dev_err(&pdev->dev, "cannot initialize irq domain\n");
++ goto err2;
++ }
++
++ /* request interrupts one by one */
++ for (k = 0; k < p->number_of_irqs; k++) {
++ if (request_irq(p->irq[k].requested_irq, irqc_irq_handler,
++ 0, name, &p->irq[k])) {
++ dev_err(&pdev->dev, "failed to request IRQ\n");
++ ret = -ENOENT;
++ goto err3;
++ }
++ }
++
++ dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs);
++
++ /* warn in case of mismatch if irq base is specified */
++ if (p->config.irq_base) {
++ if (p->config.irq_base != p->irq[0].domain_irq)
++ dev_warn(&pdev->dev, "irq base mismatch (%d/%d)\n",
++ p->config.irq_base, p->irq[0].domain_irq);
++ }
++
++ return 0;
++err3:
++ for (; k >= 0; k--)
++ free_irq(p->irq[k - 1].requested_irq, &p->irq[k - 1]);
++
++ irq_domain_remove(p->irq_domain);
++err2:
++ iounmap(p->iomem);
++err1:
++ kfree(p);
++err0:
++ return ret;
++}
++
++static int irqc_remove(struct platform_device *pdev)
++{
++ struct irqc_priv *p = platform_get_drvdata(pdev);
++ int k;
++
++ for (k = 0; k < p->number_of_irqs; k++)
++ free_irq(p->irq[k].requested_irq, &p->irq[k]);
++
++ irq_domain_remove(p->irq_domain);
++ iounmap(p->iomem);
++ kfree(p);
++ return 0;
++}
++
++static struct platform_driver irqc_device_driver = {
++ .probe = irqc_probe,
++ .remove = irqc_remove,
++ .driver = {
++ .name = "renesas_irqc",
++ }
++};
++
++static int __init irqc_init(void)
++{
++ return platform_driver_register(&irqc_device_driver);
++}
++postcore_initcall(irqc_init);
++
++static void __exit irqc_exit(void)
++{
++ platform_driver_unregister(&irqc_device_driver);
++}
++module_exit(irqc_exit);
++
++MODULE_AUTHOR("Magnus Damm");
++MODULE_DESCRIPTION("Renesas IRQC Driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/include/linux/platform_data/irq-renesas-irqc.h
+@@ -0,0 +1,27 @@
++/*
++ * Renesas IRQC Driver
++ *
++ * Copyright (C) 2013 Magnus Damm
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef __IRQ_RENESAS_IRQC_H__
++#define __IRQ_RENESAS_IRQC_H__
++
++struct renesas_irqc_config {
++ unsigned int irq_base;
++};
++
++#endif /* __IRQ_RENESAS_IRQC_H__ */
diff --git a/patches.misc/0013-ARM-shmobile-Make-r8a7779-INTC-irqpin-platform-data-.patch b/patches.misc/0013-ARM-shmobile-Make-r8a7779-INTC-irqpin-platform-data-.patch
new file mode 100644
index 00000000000..1c5862eaa67
--- /dev/null
+++ b/patches.misc/0013-ARM-shmobile-Make-r8a7779-INTC-irqpin-platform-data-.patch
@@ -0,0 +1,29 @@
+From 51d6f21fe0236a78f3a53d2603d62a2df88a3902 Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Wed, 6 Mar 2013 15:10:06 +0900
+Subject: ARM: shmobile: Make r8a7779 INTC irqpin platform data static
+
+The platform data for the INTC irq pin driver
+seems to be global symbols, make it static to
+allow multi-soc build.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+(cherry picked from commit dd09a3e6cc0c5f7cc5a05612535e55e78820f404)
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ arch/arm/mach-shmobile/intc-r8a7779.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/mach-shmobile/intc-r8a7779.c
++++ b/arch/arm/mach-shmobile/intc-r8a7779.c
+@@ -42,7 +42,7 @@
+ #define INT2NTSR0 0xfe700060
+ #define INT2NTSR1 0xfe700064
+
+-struct renesas_intc_irqpin_config irqpin0_platform_data = {
++static struct renesas_intc_irqpin_config irqpin0_platform_data = {
+ .irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */
+ .sense_bitfield_width = 2,
+ };
diff --git a/patches.misc/0014-irqchip-intc-irqpin-Initial-DT-support.patch b/patches.misc/0014-irqchip-intc-irqpin-Initial-DT-support.patch
new file mode 100644
index 00000000000..4aeb362ee9e
--- /dev/null
+++ b/patches.misc/0014-irqchip-intc-irqpin-Initial-DT-support.patch
@@ -0,0 +1,48 @@
+From c13fcfb98291d86e1f47fcb93a419f11952a873d Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Wed, 6 Mar 2013 15:16:08 +0900
+Subject: irqchip: intc-irqpin: Initial DT support
+
+Add initial DT support to the INTC External IRQ Pin
+driver. At this point only hardware with 4-bit wide
+sense registers is supported via DT.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+(cherry picked from commit 9d833bbe49953a9a07f9ebd7a9ad170c308bd692)
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/irqchip/irq-renesas-intc-irqpin.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
++++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
+@@ -278,6 +278,7 @@ static int intc_irqpin_irq_domain_map(st
+
+ static struct irq_domain_ops intc_irqpin_irq_domain_ops = {
+ .map = intc_irqpin_irq_domain_map,
++ .xlate = irq_domain_xlate_twocell,
+ };
+
+ static int intc_irqpin_probe(struct platform_device *pdev)
+@@ -437,11 +438,19 @@ static int intc_irqpin_remove(struct pla
+ return 0;
+ }
+
++static const struct of_device_id intc_irqpin_dt_ids[] = {
++ { .compatible = "renesas,intc-irqpin", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
++
+ static struct platform_driver intc_irqpin_device_driver = {
+ .probe = intc_irqpin_probe,
+ .remove = intc_irqpin_remove,
+ .driver = {
+ .name = "renesas_intc_irqpin",
++ .of_match_table = intc_irqpin_dt_ids,
++ .owner = THIS_MODULE,
+ }
+ };
+
diff --git a/patches.misc/0015-irqchip-irqc-Add-DT-support.patch b/patches.misc/0015-irqchip-irqc-Add-DT-support.patch
new file mode 100644
index 00000000000..bb90db7a824
--- /dev/null
+++ b/patches.misc/0015-irqchip-irqc-Add-DT-support.patch
@@ -0,0 +1,46 @@
+From 14bd4f0bc85992add01373d6ebed7dfabd85f07a Mon Sep 17 00:00:00 2001
+From: Magnus Damm <damm@opensource.se>
+Date: Wed, 6 Mar 2013 15:23:39 +0900
+Subject: irqchip: irqc: Add DT support
+
+Add DT support to the IRQC External IRQ Pin driver.
+
+Signed-off-by: Magnus Damm <damm@opensource.se>
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+(cherry picked from commit 3b8dfa7c2f8af7613dae28ac0f3419bf75ead5d0)
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/irqchip/irq-renesas-irqc.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/irqchip/irq-renesas-irqc.c
++++ b/drivers/irqchip/irq-renesas-irqc.c
+@@ -145,6 +145,7 @@ static int irqc_irq_domain_map(struct ir
+
+ static struct irq_domain_ops irqc_irq_domain_ops = {
+ .map = irqc_irq_domain_map,
++ .xlate = irq_domain_xlate_twocell,
+ };
+
+ static int irqc_probe(struct platform_device *pdev)
+@@ -273,11 +274,19 @@ static int irqc_remove(struct platform_d
+ return 0;
+ }
+
++static const struct of_device_id irqc_dt_ids[] = {
++ { .compatible = "renesas,irqc", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, irqc_dt_ids);
++
+ static struct platform_driver irqc_device_driver = {
+ .probe = irqc_probe,
+ .remove = irqc_remove,
+ .driver = {
+ .name = "renesas_irqc",
++ .of_match_table = irqc_dt_ids,
++ .owner = THIS_MODULE,
+ }
+ };
+
diff --git a/series b/series
index 3eba6fb2b2b..429fc322097 100644
--- a/series
+++ b/series
@@ -786,6 +786,21 @@ patches.codel/codel-refine-one-condition-to-avoid-a-nul-rec_inv_sq.patch
#
patches.misc/arm-soc-add-per-platform-smp-operations.patch
patches.misc/arm-soc-convert-shmobile-smp-to-smp-operations.patch
+patches.misc/0001-irqchip-add-basic-infrastructure.patch
+patches.misc/0002-irqdomain-augment-add_simple-to-allocate-descs.patch
+patches.misc/0003-irqdomain-stop-screaming-about-preallocated-irqdescs.patch
+patches.misc/0004-irqchip-Renesas-INTC-External-IRQ-pin-driver.patch
+patches.misc/0005-irqchip-intc-irqpin-Cache-mapped-IRQ.patch
+patches.misc/0006-ARM-shmobile-irq_pin-for-static-IRQ-pin-assignment.patch
+patches.misc/0007-ARM-shmobile-INTC-External-IRQ-pin-driver-on-r8a7779.patch
+patches.misc/0008-irqchip-intc-irqpin-Whitespace-fixes.patch
+patches.misc/0009-irqchip-intc-irqpin-Add-force-comments.patch
+patches.misc/0010-irqchip-intc-irqpin-Make-use-of-devm-functions.patch
+patches.misc/0011-irqchip-intc-irqpin-GPL-header-for-platform-data.patch
+patches.misc/0012-irqchip-Renesas-IRQC-driver.patch
+patches.misc/0013-ARM-shmobile-Make-r8a7779-INTC-irqpin-platform-data-.patch
+patches.misc/0014-irqchip-intc-irqpin-Initial-DT-support.patch
+patches.misc/0015-irqchip-irqc-Add-DT-support.patch
#############################################################################