From patchwork Sun Mar 17 13:07:58 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heiko Stuebner X-Patchwork-Id: 2283511 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id 86B823FD8C for ; Sun, 17 Mar 2013 13:11:12 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UHDJs-00014Y-N3; Sun, 17 Mar 2013 13:08:12 +0000 Received: from gloria.sntech.de ([95.129.55.99]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UHDJl-00012U-It for linux-arm-kernel@lists.infradead.org; Sun, 17 Mar 2013 13:08:07 +0000 Received: from 146-52-57-5-dynip.superkabel.de ([146.52.57.5] helo=marty.localnet) by gloria.sntech.de with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.72) (envelope-from ) id 1UHDJg-0004tr-HQ; Sun, 17 Mar 2013 14:08:00 +0100 From: Heiko =?utf-8?q?St=C3=BCbner?= To: Kukjin Kim Subject: [PATCH v3 5/6] irqchip: s3c24xx: add devicetree support Date: Sun, 17 Mar 2013 14:07:58 +0100 User-Agent: KMail/1.13.7 (Linux/3.2.0-3-686-pae; KDE/4.8.4; i686; ; ) References: <201303171404.06146.heiko@sntech.de> In-Reply-To: <201303171404.06146.heiko@sntech.de> MIME-Version: 1.0 Message-Id: <201303171407.59128.heiko@sntech.de> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130317_090805_738163_769B5053 X-CRM114-Status: GOOD ( 23.17 ) X-Spam-Score: -4.4 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.4 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.5 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: linux-samsung-soc@vger.kernel.org, devicetree-discuss@lists.ozlabs.org, Rob Herring , Grant Likely , Thomas Abraham , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Add the necessary code to initialize the interrupt controller thru devicetree data using the irqchip infrastructure. On dt machines the eint-type interrupts in the main interrupt controller get mapped as regular edge-types, as their wakeup and interrupt type properties will be handled by the upcoming pinctrl driver. Signed-off-by: Heiko Stuebner --- .../interrupt-controller/samsung,s3c24xx-irq.txt | 54 +++++ drivers/irqchip/irq-s3c24xx.c | 222 ++++++++++++++++++++ 2 files changed, 276 insertions(+), 0 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..be5dead --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt @@ -0,0 +1,54 @@ +Samsung S3C24XX Interrupt Controllers + +The S3C24XX SoCs contain a custom set of interrupt controllers providing a +varying number of interrupt sources. The set consists of a main- and sub- +controller and on newer SoCs even a second main controller. + +Required properties: +- compatible: Compatible property value should be one of "samsung,s3c2410-irq", + "samsung,s3c2412-irq", "samsung,s3c2416-irq", "samsung,s3c2440-irq", + "samsung,s3c2442-irq", "samsung,s3c2443-irq" depending on the SoC variant. + +- reg: Physical base address of the controller and length of memory mapped + region. + +- interrupt-controller : Identifies the node as an interrupt controller + +Sub-controllers as child nodes: + The interrupt controllers that should be referenced by device nodes are + represented by child nodes. Valid names are intc, subintc and intc2. + The interrupt values in device nodes are then mapped directly to the + bit-numbers of the pending register of the named interrupt controller. + +Required properties: +- 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. + +Example: + + interrupt-controller@4a000000 { + compatible = "samsung,s3c2416-irq"; + reg = <0x4a000000 0x100>; + interrupt-controller; + + intc:intc { + interrupt-controller; + #interrupt-cells = <2>; + }; + + subintc:subintc { + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + [...] + + serial@50000000 { + compatible = "samsung,s3c2410-uart"; + reg = <0x50000000 0x4000>; + interrupt-parent = <&subintc>; + interrupts = <0 0>, <1 0>; + }; diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c index 1eba289..55cb363 100644 --- a/drivers/irqchip/irq-s3c24xx.c +++ b/drivers/irqchip/irq-s3c24xx.c @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include @@ -36,6 +39,8 @@ #include #include +#include "irqchip.h" + #define S3C_IRQTYPE_NONE 0 #define S3C_IRQTYPE_EINT 1 #define S3C_IRQTYPE_EDGE 2 @@ -380,6 +385,10 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq, parent_intc = intc->parent; + /* on dt platforms the extints get handled by the pinctrl driver */ + if (h->of_node && irq_data->type == S3C_IRQTYPE_EINT) + irq_data->type = S3C_IRQTYPE_EDGE; + /* set handler and flags */ switch (irq_data->type) { case S3C_IRQTYPE_NONE: @@ -1104,3 +1113,216 @@ void __init s3c2443_init_irq(void) s3c24xx_init_intc(NULL, &init_s3c2443subint[0], main_intc, 0x4a000018); } #endif + +#ifdef CONFIG_OF +struct s3c24xx_irq_of_ctrl { + char *name; + unsigned long offset; + struct s3c_irq_data *irq_data; + struct s3c_irq_intc **handle; + struct s3c_irq_intc **parent; +}; + +#define S3C24XX_IRQCTRL(n, o, d, h, p) \ +{ \ + .name = n, \ + .offset = o, \ + .irq_data = d, \ + .handle = h, \ + .parent = p, \ +} + +struct s3c24xx_irq_of_data { + struct s3c24xx_irq_of_ctrl *irq_ctrl; + int num_ctrl; +}; + +#ifdef CONFIG_CPU_S3C2410 +static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = { + S3C24XX_IRQCTRL("intc", 0, init_s3c2410base, &main_intc, NULL), + S3C24XX_IRQCTRL("subintc", 0x18, init_s3c2410subint, NULL, &main_intc), +}; + +static struct s3c24xx_irq_of_data s3c2410_irq_data = { + .irq_ctrl = s3c2410_ctrl, + .num_ctrl = ARRAY_SIZE(s3c2410_ctrl), +}; +#endif + +#ifdef CONFIG_CPU_S3C2412 +static struct s3c24xx_irq_of_ctrl s3c2412_ctrl[] = { + S3C24XX_IRQCTRL("intc", 0, init_s3c2412base, &main_intc, NULL), + S3C24XX_IRQCTRL("subintc", 0x18, init_s3c2412subint, NULL, &main_intc), +}; + +static struct s3c24xx_irq_of_data s3c2412_irq_data = { + .irq_ctrl = s3c2412_ctrl, + .num_ctrl = ARRAY_SIZE(s3c2412_ctrl), +}; +#endif + +#ifdef CONFIG_CPU_S3C2416 +static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = { + S3C24XX_IRQCTRL("intc", 0, init_s3c2416base, &main_intc, NULL), + S3C24XX_IRQCTRL("subintc", 0x18, init_s3c2416subint, NULL, &main_intc), + S3C24XX_IRQCTRL("intc2", 0x40, init_s3c2416_second, &main_intc2, NULL), +}; + +static struct s3c24xx_irq_of_data s3c2416_irq_data = { + .irq_ctrl = s3c2416_ctrl, + .num_ctrl = ARRAY_SIZE(s3c2416_ctrl), +}; +#endif + +#ifdef CONFIG_CPU_S3C2440 +static struct s3c24xx_irq_of_ctrl s3c2440_ctrl[] = { + S3C24XX_IRQCTRL("intc", 0, init_s3c2440base, &main_intc, NULL), + S3C24XX_IRQCTRL("subintc", 0x18, init_s3c2440subint, NULL, &main_intc), +}; + +static struct s3c24xx_irq_of_data s3c2440_irq_data = { + .irq_ctrl = s3c2440_ctrl, + .num_ctrl = ARRAY_SIZE(s3c2440_ctrl), +}; +#endif + +#ifdef CONFIG_CPU_S3C2442 +static struct s3c24xx_irq_of_ctrl s3c2442_ctrl[] = { + S3C24XX_IRQCTRL("intc", 0, init_s3c2442base, &main_intc, NULL), + S3C24XX_IRQCTRL("subintc", 0x18, init_s3c2442subint, NULL, &main_intc), +}; + +static struct s3c24xx_irq_of_data s3c2442_irq_data = { + .irq_ctrl = s3c2442_ctrl, + .num_ctrl = ARRAY_SIZE(s3c2442_ctrl), +}; +#endif + +#ifdef CONFIG_CPU_S3C2443 +static struct s3c24xx_irq_of_ctrl s3c2443_ctrl[] = { + S3C24XX_IRQCTRL("intc", 0, init_s3c2443base, &main_intc, NULL), + S3C24XX_IRQCTRL("subintc", 0x18, init_s3c2443subint, NULL, &main_intc), +}; + +static struct s3c24xx_irq_of_data s3c2443_irq_data = { + .irq_ctrl = s3c2443_ctrl, + .num_ctrl = ARRAY_SIZE(s3c2443_ctrl), +}; +#endif + +static const struct of_device_id intc_list[] = { +#ifdef CONFIG_CPU_S3C2410 + { .compatible = "samsung,s3c2410-irq", .data = &s3c2410_irq_data }, +#endif +#ifdef CONFIG_CPU_S3C2412 + { .compatible = "samsung,s3c2412-irq", .data = &s3c2412_irq_data }, +#endif +#ifdef CONFIG_CPU_S3C2416 + { .compatible = "samsung,s3c2416-irq", .data = &s3c2416_irq_data }, +#endif +#ifdef CONFIG_CPU_S3C2440 + { .compatible = "samsung,s3c2440-irq", .data = &s3c2440_irq_data }, +#endif +#ifdef CONFIG_CPU_S3C2442 + { .compatible = "samsung,s3c2442-irq", .data = &s3c2442_irq_data }, +#endif +#ifdef CONFIG_CPU_S3C2443 + { .compatible = "samsung,s3c2443-irq", .data = &s3c2443_irq_data }, +#endif + {}, +}; + +int __init s3c24xx_init_intc_of(struct device_node *np, + struct device_node *interrupt_parent) +{ + const struct of_device_id *match; + const struct s3c24xx_irq_of_data *ctrl_data; + struct device_node *intc_node; + struct s3c24xx_irq_of_ctrl *ctrl; + struct s3c_irq_intc *intc; + void __iomem *reg_base; + int i; + + match = of_match_node(intc_list, np); + if (!match) { + pr_err("irq-s3c24xx: could not find matching irqdata\n"); + return -EINVAL; + } + + ctrl_data = match->data; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("irq-s3c24xx: could not map irq memory\n"); + return -EINVAL; + } + + for (i = 0; i < ctrl_data->num_ctrl; i++) { + ctrl = &ctrl_data->irq_ctrl[i]; + + intc_node = of_find_node_by_name(np, ctrl->name); + if (!intc_node) { + pr_debug("irq: no device node for %s\n", + ctrl->name); + continue; + } + + intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL); + if (!intc) { + of_node_put(intc_node); + return -ENOMEM; + } + + pr_debug("irq: found controller %s\n", ctrl->name); + + intc->irqs = ctrl->irq_data; + + if (ctrl->parent) { + if (*(ctrl->parent)) { + intc->parent = *(ctrl->parent); + } else { + pr_warn("irq: parent of %s missing\n", + ctrl->name); + kfree(intc); + of_node_put(intc_node); + continue; + } + } + + if (!ctrl->parent) { + intc->reg_pending = reg_base + ctrl->offset; + intc->reg_mask = reg_base + ctrl->offset + 0x08; + intc->reg_intpnd = reg_base + ctrl->offset + 0x10; + } else { + intc->reg_pending = reg_base + ctrl->offset; + intc->reg_mask = reg_base + ctrl->offset + 0x4; + } + + /* now that all the data is complete, init the irq-domain */ + s3c24xx_clear_intc(intc); + intc->domain = irq_domain_add_linear(intc_node, 32, + &s3c24xx_irq_ops, intc); + if (!intc->domain) { + pr_err("irq: could not create irq-domain\n"); + kfree(intc); + of_node_put(intc_node); + continue; + } + + if (ctrl->handle) + *(ctrl->handle) = intc; + } + + set_handle_irq(s3c24xx_handle_irq); + + return 0; +} + +IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c24xx_init_intc_of); +IRQCHIP_DECLARE(s3c2412_irq, "samsung,s3c2412-irq", s3c24xx_init_intc_of); +IRQCHIP_DECLARE(s3c2416_irq, "samsung,s3c2416-irq", s3c24xx_init_intc_of); +IRQCHIP_DECLARE(s3c2440_irq, "samsung,s3c2440-irq", s3c24xx_init_intc_of); +IRQCHIP_DECLARE(s3c2442_irq, "samsung,s3c2442-irq", s3c24xx_init_intc_of); +IRQCHIP_DECLARE(s3c2443_irq, "samsung,s3c2443-irq", s3c24xx_init_intc_of); +IRQCHIP_DECLARE(s3c2450_irq, "samsung,s3c2450-irq", s3c24xx_init_intc_of); +#endif