From patchwork Fri Sep 21 14:22:54 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Figa X-Patchwork-Id: 1491731 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 3DE6DDF28C for ; Fri, 21 Sep 2012 14:26:05 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TF48z-0002Ek-8x; Fri, 21 Sep 2012 14:23:49 +0000 Received: from mailout4.samsung.com ([203.254.224.34]) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TF48v-0002Ds-5d for linux-arm-kernel@lists.infradead.org; Fri, 21 Sep 2012 14:23:46 +0000 Received: from epcpsbgm2.samsung.com (epcpsbgm2 [203.254.230.27]) by mailout4.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MAP00JIKENGCHZ0@mailout4.samsung.com> for linux-arm-kernel@lists.infradead.org; Fri, 21 Sep 2012 23:23:40 +0900 (KST) X-AuditID: cbfee61b-b7f2b6d000000f14-12-505c786cefce Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id A4.DB.03860.C687C505; Fri, 21 Sep 2012 23:23:40 +0900 (KST) Received: from mcdsrvbld02.digital.local ([106.116.37.23]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MAP0020KEMM3N30@mmp1.samsung.com> for linux-arm-kernel@lists.infradead.org; Fri, 21 Sep 2012 23:23:40 +0900 (KST) From: Tomasz Figa To: linux-arm-kernel@lists.infradead.org Subject: [RFC PATCH 3/6] pinctrl: exynos: Use one IRQ domain per pin bank Date: Fri, 21 Sep 2012 16:22:54 +0200 Message-id: <1348237377-21299-4-git-send-email-t.figa@samsung.com> X-Mailer: git-send-email 1.7.10 In-reply-to: <1348237377-21299-1-git-send-email-t.figa@samsung.com> References: <1348237377-21299-1-git-send-email-t.figa@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrIJMWRmVeSWpSXmKPExsVy+t9jAd2cipgAg7PXJSw2Pb7G6sDosXlJ fQBjFJdNSmpOZllqkb5dAlfGjqOXmAq2BFecebyKuYHxt0sXIyeHhICJRPP9e0wQtpjEhXvr 2boYuTiEBBYxSsxbOpcJwtnMJPFz2j5WkCo2ATWJzw2P2EBsEQENiSldj9lBbGaByUwSxxak g9jCAp4SE49MYOxi5OBgEVCVmLQZLMwr4CTxesVlRohl8hJP7/eBjeEUcJa4uasDbIwQUM33 hR3MExh5FzAyrGIUTS1ILihOSs810itOzC0uzUvXS87P3cQI9vgz6R2MqxosDjEKcDAq8fCu +BYdIMSaWFZcmXuIUYKDWUmE91EMUIg3JbGyKrUoP76oNCe1+BCjNAeLkjiv8KfAACGB9MSS 1OzU1ILUIpgsEwenVAOjNqvy/lfrtAqsJdXuRTTd2XRR49y14Dub//oLzpi3+yrLug/FexoU sr4t0X+XcDVx/a2FszbyxHP29GlriiR3yFVdemZw/FLBgrc+bK/Lr8fuW6kUU55l06yZxXF0 ufbTlNpFc7arOEz44b6jP2Xt63WvuuIjbXy7+14sXfxM+Md70xkH2iouKLEUZyQaajEXFScC AF7VDNH0AQAA X-Spam-Note: CRM114 invocation failed X-Spam-Score: -7.4 (-------) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-7.4 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [203.254.224.34 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.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: kgene.kim@samsung.com, swarren@wwwdotorg.org, devicetree-discuss@lists.ozlabs.org, tomasz.figa@gmail.com, t.figa@samsung.com, kyungmin.park@samsung.com, linux-samsung-soc@vger.kernel.org, thomas.abraham@linaro.org, linus.walleij@linaro.org, m.szyprowski@samsung.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Instead of registering one IRQ domain for all pin banks of a pin controller, this patch implements registration of per-bank domains. At a cost of a little memory overhead (~2.5KiB for all GPIO interrupts of Exynos4x12) it simplifies driver code and device tree sources, because GPIO interrupts can be now specified per banks. Example: device { /* ... */ interrupt-parent = <&gpa1>; interrupts = <3 0>; /* ... */ }; Signed-off-by: Tomasz Figa --- drivers/pinctrl/pinctrl-exynos.c | 118 +++++++++++--------------------------- drivers/pinctrl/pinctrl-exynos.h | 12 ---- drivers/pinctrl/pinctrl-samsung.c | 4 +- drivers/pinctrl/pinctrl-samsung.h | 5 +- 4 files changed, 37 insertions(+), 102 deletions(-) diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 340bfc2..2f8427f 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -40,46 +40,46 @@ static const struct of_device_id exynos_wkup_irq_ids[] = { static void exynos_gpio_irq_unmask(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; + struct samsung_pin_bank *bank = irq_data_get_irq_handler_data(irqd); + struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); + unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset; unsigned long mask; mask = readl(d->virt_base + reg_mask); - mask &= ~(1 << edata->pin); + mask &= ~(1 << irqd->hwirq); writel(mask, d->virt_base + reg_mask); } static void exynos_gpio_irq_mask(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; + struct samsung_pin_bank *bank = irq_data_get_irq_handler_data(irqd); + struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); + unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset; unsigned long mask; mask = readl(d->virt_base + reg_mask); - mask |= 1 << edata->pin; + mask |= 1 << irqd->hwirq; writel(mask, d->virt_base + reg_mask); } static void exynos_gpio_irq_ack(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - unsigned long reg_pend = d->ctrl->geint_pend + edata->eint_offset; + struct samsung_pin_bank *bank = irq_data_get_irq_handler_data(irqd); + struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); + unsigned long reg_pend = d->ctrl->geint_pend + bank->eint_offset; - writel(1 << edata->pin, d->virt_base + reg_pend); + writel(1 << irqd->hwirq, d->virt_base + reg_pend); } static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; + struct samsung_pin_bank *bank = irq_data_get_irq_handler_data(irqd); + struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); struct samsung_pin_ctrl *ctrl = d->ctrl; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - struct samsung_pin_bank *bank = edata->bank; - unsigned int shift = EXYNOS_EINT_CON_LEN * edata->pin; + unsigned int pin = irqd->hwirq; + unsigned int shift = EXYNOS_EINT_CON_LEN * pin; unsigned int con, trig_type; - unsigned long reg_con = ctrl->geint_con + edata->eint_offset; + unsigned long reg_con = ctrl->geint_con + bank->eint_offset; unsigned int mask; switch (type) { @@ -114,7 +114,7 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) writel(con, d->virt_base + reg_con); reg_con = bank->pctl_offset; - shift = edata->pin * bank->func_width; + shift = pin * bank->func_width; mask = (1 << bank->func_width) - 1; con = readl(d->virt_base + reg_con); @@ -136,81 +136,24 @@ static struct irq_chip exynos_gpio_irq_chip = { .irq_set_type = exynos_gpio_irq_set_type, }; -/* - * given a controller-local external gpio interrupt number, prepare the handler - * data for it. - */ -static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw, - struct samsung_pinctrl_drv_data *d) -{ - struct samsung_pin_bank *bank = d->ctrl->pin_banks; - struct exynos_geint_data *eint_data; - unsigned int nr_banks = d->ctrl->nr_banks, idx; - unsigned int irq_base = 0; - - if (hw >= d->ctrl->nr_gint) { - dev_err(d->dev, "unsupported ext-gpio interrupt\n"); - return NULL; - } - - for (idx = 0; idx < nr_banks; idx++, bank++) { - if (bank->eint_type != EINT_TYPE_GPIO) - continue; - if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins))) - break; - irq_base += bank->nr_pins; - } - - if (idx == nr_banks) { - dev_err(d->dev, "pin bank not found for ext-gpio interrupt\n"); - return NULL; - } - - eint_data = devm_kzalloc(d->dev, sizeof(*eint_data), GFP_KERNEL); - if (!eint_data) { - dev_err(d->dev, "no memory for eint-gpio data\n"); - return NULL; - } - - eint_data->bank = bank; - eint_data->pin = hw - irq_base; - eint_data->eint_offset = bank->eint_offset; - return eint_data; -} - static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { - struct samsung_pinctrl_drv_data *d = h->host_data; - struct exynos_geint_data *eint_data; + struct samsung_pin_bank *b = h->host_data; - eint_data = exynos_get_eint_data(hw, d); - if (!eint_data) - return -EINVAL; - - irq_set_handler_data(virq, eint_data); - irq_set_chip_data(virq, h->host_data); + irq_set_handler_data(virq, b); + irq_set_chip_data(virq, b->drvdata); irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip, handle_level_irq); set_irq_flags(virq, IRQF_VALID); return 0; } -static void exynos_gpio_irq_unmap(struct irq_domain *h, unsigned int virq) -{ - struct samsung_pinctrl_drv_data *d = h->host_data; - struct exynos_geint_data *eint_data; - - eint_data = irq_get_handler_data(virq); - devm_kfree(d->dev, eint_data); -} - /* * irq domain callbacks for external gpio interrupt controller. */ static const struct irq_domain_ops exynos_gpio_irqd_ops = { .map = exynos_gpio_irq_map, - .unmap = exynos_gpio_irq_unmap, .xlate = irq_domain_xlate_twocell, }; @@ -229,7 +172,7 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) return IRQ_HANDLED; bank += (group - 1); - virq = irq_linear_revmap(d->gpio_irqd, bank->irq_base + pin); + virq = irq_linear_revmap(bank->gpio_irqd, pin); if (!virq) return IRQ_NONE; generic_handle_irq(virq); @@ -242,8 +185,10 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) */ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) { + struct samsung_pin_bank *bank; struct device *dev = d->dev; unsigned int ret; + unsigned int i; if (!d->irq) { dev_err(dev, "irq number not available\n"); @@ -257,11 +202,16 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) return -ENXIO; } - d->gpio_irqd = irq_domain_add_linear(dev->of_node, d->ctrl->nr_gint, - &exynos_gpio_irqd_ops, d); - if (!d->gpio_irqd) { - dev_err(dev, "gpio irq domain allocation failed\n"); - return -ENXIO; + bank = d->ctrl->pin_banks; + for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + if (bank->eint_type != EINT_TYPE_GPIO) + continue; + bank->gpio_irqd = irq_domain_add_linear(bank->of_node, + bank->nr_pins, &exynos_gpio_irqd_ops, bank); + if (!bank->gpio_irqd) { + dev_err(dev, "gpio irq domain add failed\n"); + return -ENXIO; + } } return 0; diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h index a72cfc7..30aca2b 100644 --- a/drivers/pinctrl/pinctrl-exynos.h +++ b/drivers/pinctrl/pinctrl-exynos.h @@ -38,18 +38,6 @@ #define EXYNOS_EINT_MAX_PER_BANK 8 /** - * struct exynos_geint_data: gpio eint specific data for irq_chip callbacks. - * @bank: pin bank from which this gpio interrupt originates. - * @pin: pin number within the bank. - * @eint_offset: offset to be added to the con/pend/mask register bank base. - */ -struct exynos_geint_data { - struct samsung_pin_bank *bank; - u32 pin; - u32 eint_offset; -}; - -/** * struct exynos_weint_data: irq specific data for all the wakeup interrupts * generated by the external wakeup interrupt controller. * @domain: irq domain representing the external wakeup interrupts diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 3f48d3f..a6c219a 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -899,10 +899,8 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( b->drvdata = d; b->pin_base = ctrl->nr_pins; ctrl->nr_pins += b->nr_pins; - if (of_find_property(bank_np, "interrupt-controller", NULL)) { - b->irq_base = eint_cnt; + if (of_find_property(bank_np, "interrupt-controller", NULL)) eint_cnt += b->nr_pins; - } ++b; } diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index 9e30081..7dbdef9 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -109,10 +109,10 @@ struct samsung_pinctrl_drv_data; * @conpdn_width: width of the sleep mode function selector bin field. * @pudpdn_width: width of the sleep mode pull up/down selector bit field. * @eint_type: type of the external interrupt supported by the bank. - * @irq_base: starting controller local irq number of the bank. * @name: name to be prefixed for each pin in this pin bank. * @of_node: node of pin bank in device tree * @drvdata: link to controller driver data + * @gpio_irqd: GPIO IRQ domain of pin bank */ struct samsung_pin_bank { u32 pctl_offset; @@ -125,11 +125,11 @@ struct samsung_pin_bank { u8 pudpdn_width; enum eint_type eint_type; u32 eint_offset; - u32 irq_base; const char *name; struct device_node *of_node; struct samsung_pinctrl_drv_data *drvdata; + struct irq_domain *gpio_irqd; }; /** @@ -218,7 +218,6 @@ struct samsung_pinctrl_drv_data { const struct samsung_pmx_func *pmx_functions; unsigned int nr_functions; - struct irq_domain *gpio_irqd; struct irq_domain *wkup_irqd; struct gpio_chip *gc;