This adds devicetree parsing of the controller-data for the
interrupt controllers on S3C24XX architectures.

As the interrupts and their parent differ on all s3c24xx SoCs the
interrupt-list and parent-relationship is read from a list in the
devicetree data.

Signed-off-by: Heiko Stuebner <he...@sntech.de>
---
 .../interrupt-controller/samsung,s3c24xx-irq.txt   |   53 ++++++++
 drivers/irqchip/Makefile                           |    2 +-
 drivers/irqchip/irq-s3c24xx.c                      |  128 ++++++++++++++++++++
 3 files changed, 182 insertions(+), 1 deletions(-)
 create mode 100644 
Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt
 
b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt
new file mode 100644
index 0000000..3f6600e
--- /dev/null
+++ 
b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt
@@ -0,0 +1,53 @@
+Samsung S3C24XX Interrupt Controllers
+
+The S3C24XX SoCs contain custom set of interrupt controllers providing a
+varying number of interrupt sources.
+
+The set consists of a main- and a sub-controller as well as a controller
+for the external interrupts and on newer SoCs even a second main controller.
+
+The bit-to-interrupt and parent mapping of the controllers is not fixed
+over all SoCs and therefore must be defined in the controller description.
+
+Required properties:
+- compatible: Compatible property value should be "samsung,s3c24xx-irq".
+
+- reg: Physical base address of the controller and length of memory mapped
+  region.
+
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value shall be 2.
+
+- s3c24xx,irqlist : List of irqtypes found on this controller as
+  two-value pairs consisting of irqtype and parent-irq number
+
+  parent-irq is always the list position of the irq in the irqlist
+  of the parent controller (0..31)
+
+  irqtypes are:
+  - 0 .. none
+  - 1 .. external interrupts
+  - 2 .. edge irq
+  - 3 .. level irq
+
+Optional properties:
+- interrupt_parent : The parent interrupt controller
+
+Example:
+
+       intc2:interrupt-controller@4a000040 {
+               compatible = "samsung,s3c24xx-irq";
+               reg = <0x4a000040 0x18>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+
+               s3c24xx,irqlist = <2 0 /* 2D */
+                                  2 0 /* IIC1 */
+                                  0 0 /* reserved */
+                                  0 0 /* reserved */
+                                  2 0 /* PCM0 */
+                                  2 0 /* PCM1 */
+                                  2 0 /* I2S0 */
+                                  2 0>; /* I2S1 */
+       };
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 073324c..7ce9f05 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -4,7 +4,7 @@ obj-$(CONFIG_ARCH_BCM2835)              += irq-bcm2835.o
 obj-$(CONFIG_METAG)                    += irq-metag-ext.o
 obj-$(CONFIG_METAG_PERFCOUNTER_IRQS)   += irq-metag.o
 obj-$(CONFIG_ARCH_EXYNOS)              += exynos-combiner.o
-obj-$(CONFIG_ARCH_S3C24XX)             += irq-s3c24xx.c
+obj-$(CONFIG_ARCH_S3C24XX)             += irq-s3c24xx.o
 obj-$(CONFIG_ARCH_SUNXI)               += irq-sunxi.o
 obj-$(CONFIG_ARCH_SPEAR3XX)            += spear-shirq.o
 obj-$(CONFIG_ARM_GIC)                  += irq-gic.o
diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c
index 3f3de74..2a02de3 100644
--- a/drivers/irqchip/irq-s3c24xx.c
+++ b/drivers/irqchip/irq-s3c24xx.c
@@ -25,6 +25,9 @@
 #include <linux/ioport.h>
 #include <linux/device.h>
 #include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
 
 #include <asm/mach/irq.h>
 
@@ -35,6 +38,8 @@
 #include <plat/regs-irqtype.h>
 #include <plat/pm.h>
 
+#include "irqchip.h"
+
 #define S3C_IRQTYPE_NONE       0
 #define S3C_IRQTYPE_EINT       1
 #define S3C_IRQTYPE_EDGE       2
@@ -1066,3 +1071,126 @@ void __init s3c2443_init_irq(void)
        s3c24xx_init_intc(NULL, &init_s3c2443subint[0], main_intc, 0x4a000018);
 }
 #endif
+
+#ifdef CONFIG_OF
+int __init s3c24xx_init_intc_of(struct device_node *np,
+                                struct device_node *interrupt_parent)
+{
+       struct s3c_irq_intc *intc;
+       struct s3c_irq_intc *parent;
+       struct s3c_irq_data *irq_data;
+       struct property *intc_prop;
+       const __be32 *p;
+       unsigned long address;
+       int ret;
+       int i;
+       int cnt;
+       u32 val;
+
+       p = of_get_address(np, 0, NULL, NULL);
+       if (!p) {
+               pr_err("irq: register address missing\n");
+               return -EINVAL;
+       }
+
+       address = of_translate_address(np, p);
+
+       intc_prop = of_find_property(np, "s3c24xx,irqlist", NULL);
+       if (!intc_prop) {
+               pr_err("irq: irqlist not found\n");
+               return -EINVAL;
+       }
+
+       irq_data = kzalloc(sizeof(struct s3c_irq_data) * 32, GFP_KERNEL);
+       if (!irq_data)
+               return -ENOMEM;
+
+       /* build the irq_data list */
+       p = NULL;
+       cnt = 0;
+       for (i = 0; i < 32; i++) {
+               p = of_prop_next_u32(intc_prop, p, &val);
+
+               /* when we hit the first non-valid element, assume it's
+                * the end of the list. The rest of the fields are
+                * already of type S3C_IRQTYPE_NONE (value 0)
+                */
+               if (!p)
+                       break;
+
+               irq_data[i].type = val;
+
+               p = of_prop_next_u32(intc_prop, p, &val);
+               if (!p) {
+                       pr_warn("irq: uneven number of elements in irqlist, 
last interrupt will be dropped\n");
+                       irq_data[i].type = 0;
+                       break;
+               }
+
+               irq_data[i].parent_irq = val;
+
+               pr_debug("irq: found hwirq %d with type %d and parent %lu\n",
+                        i, irq_data[i].type, irq_data[i].parent_irq);
+               cnt++;
+       }
+
+       /* if we haven't found any irq definition at all,
+        * something is very wrong.
+        */
+       if (!cnt) {
+               pr_err("irq: empty irq definition\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       if (interrupt_parent) {
+               parent = (struct s3c_irq_intc *)of_get_property(
+                                     interrupt_parent, "s3c-irq-intc", NULL);
+               if (!parent) {
+                       pr_err("irq: no parent for non-root controller 
found\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+       } else {
+               parent = NULL;
+       }
+
+       intc = s3c24xx_init_intc(np, irq_data, parent, address);
+       if (IS_ERR(intc)) {
+               ret = PTR_ERR(intc);
+               goto err;
+       }
+
+       /* put the intc as property into the dt, so we can access it
+        * as the interrupt_parent later
+        */
+       intc_prop = kzalloc(sizeof(struct property), GFP_KERNEL);
+       if (!intc_prop) {
+               pr_err("irq: could not allocate memory for dt property\n");
+
+               /* the interrupt controller was already added, so don't
+                * remove the created structures.
+                */
+               return -ENOMEM;
+       }
+
+       intc_prop->name = kstrdup("s3c-irq-intc", GFP_KERNEL);
+       intc_prop->value = intc;
+       intc_prop->length = sizeof(struct s3c_irq_intc);
+
+       ret = of_add_property(np, intc_prop);
+       if (ret) {
+               pr_err("irq: failed to add dt property\n");
+               kfree(intc_prop);
+               return ret;
+       }
+
+       return 0;
+
+err:
+       kfree(irq_data);
+
+       return ret;
+}
+IRQCHIP_DECLARE(s3c24xx_irq, "samsung,s3c24xx-irq", s3c24xx_init_intc_of);
+#endif
-- 
1.7.2.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to