From patchwork Fri Sep 7 11:14:58 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lee Jones X-Patchwork-Id: 11252 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 0A7E523F25 for ; Fri, 7 Sep 2012 11:15:45 +0000 (UTC) Received: from mail-ie0-f180.google.com (mail-ie0-f180.google.com [209.85.223.180]) by fiordland.canonical.com (Postfix) with ESMTP id 70DAAA18A94 for ; Fri, 7 Sep 2012 11:15:44 +0000 (UTC) Received: by mail-ie0-f180.google.com with SMTP id k11so4488374iea.11 for ; Fri, 07 Sep 2012 04:15:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=O8lvOIIRZQEwm42Qq2QF8iSQbiGZ2v4qi1ICvH8pNb8=; b=A8Y1OGoR+CKW1tiimDFCkzNFiSZqZJTKDab3JXeaxP0m3M0M524qFvNECYowQT4sFy iICpGkcDt+c3gIBD6JC6K0OpRrhOKlqfpR6Upk3mT6m1OmwciarXi4RDageQ+eQ2xJvi Y/o0Hcp6g7/9191eOrr+/nQ6ZuqDW2O1tUtrrfipmrboGRTfJG1qyYu42ktX+wDlunpw h+lfY+ZPqLgEE8JEjsyupMtBozKr0iSaPp9wsMzjITjAJfoLQQ/GneMCx7ujbae0k78K uAa2BbrWDoeuarY8KeZwhXCK7yzc61gy5oASycfAK5kyW0SbefAs0j0xejtd9HTL2SDJ D66A== Received: by 10.42.60.139 with SMTP id q11mr6426797ich.53.1347016544225; Fri, 07 Sep 2012 04:15:44 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.50.184.232 with SMTP id ex8csp373473igc; Fri, 7 Sep 2012 04:15:43 -0700 (PDT) Received: by 10.180.87.34 with SMTP id u2mr52502188wiz.3.1347016542809; Fri, 07 Sep 2012 04:15:42 -0700 (PDT) Received: from mail-wi0-f178.google.com (mail-wi0-f178.google.com [209.85.212.178]) by mx.google.com with ESMTPS id s83si6517548wen.78.2012.09.07.04.15.42 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 07 Sep 2012 04:15:42 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.212.178 is neither permitted nor denied by best guess record for domain of lee.jones@linaro.org) client-ip=209.85.212.178; Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.178 is neither permitted nor denied by best guess record for domain of lee.jones@linaro.org) smtp.mail=lee.jones@linaro.org Received: by mail-wi0-f178.google.com with SMTP id hr14so2068092wib.13 for ; Fri, 07 Sep 2012 04:15:42 -0700 (PDT) Received: by 10.216.68.2 with SMTP id k2mr2890078wed.69.1347016540783; Fri, 07 Sep 2012 04:15:40 -0700 (PDT) Received: from localhost.localdomain (cpc1-aztw13-0-0-cust473.18-1.cable.virginmedia.com. [77.102.241.218]) by mx.google.com with ESMTPS id k20sm9151505wiv.11.2012.09.07.04.15.39 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 07 Sep 2012 04:15:40 -0700 (PDT) From: Lee Jones To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: STEricsson_nomadik_linux@list.st.com, linus.walleij@stericsson.com, arnd@arndb.de, Lee Jones , Grant Likely Subject: [PATCH 18/19] gpio: Provide the tc3589x GPIO expander driver with an IRQ domain Date: Fri, 7 Sep 2012 12:14:58 +0100 Message-Id: <1347016499-29354-19-git-send-email-lee.jones@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1347016499-29354-1-git-send-email-lee.jones@linaro.org> References: <1347016499-29354-1-git-send-email-lee.jones@linaro.org> X-Gm-Message-State: ALoCoQmr/y7zkdOT8GJcuOhnsyOp1Y3SYBJF1WBii0DbYXkqk+ooeBhWXmk154KIqBQkx5wXNtfE In preparation for Device Tree enablement all IRQ controllers should control their own IRQ domain. This patch provides just that for the tc3589x GPIO expander. CC: Grant Likely Signed-off-by: Lee Jones --- drivers/gpio/gpio-tc3589x.c | 98 ++++++++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 28 deletions(-) diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 2a82e89..6e89009 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,7 @@ struct tc3589x_gpio { struct tc3589x *tc3589x; struct device *dev; struct mutex irq_lock; + struct irq_domain *domain; int irq_base; @@ -92,11 +94,28 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip, return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); } +/** + * tc3589x_gpio_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ + * + * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on. + * @irq: index of the interrupt requested in the chip IRQs + * + * Useful for drivers to request their own IRQs. + */ +static int tc3589x_gpio_irq_get_virq(struct tc3589x_gpio *tc3589x_gpio, + int irq) +{ + if (!tc3589x_gpio) + return -EINVAL; + + return irq_create_mapping(tc3589x_gpio->domain, irq); +} + static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); - return tc3589x_gpio->irq_base + offset; + return tc3589x_gpio_irq_get_virq(tc3589x_gpio, offset); } static struct gpio_chip template_chip = { @@ -113,7 +132,7 @@ static struct gpio_chip template_chip = { static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - tc3589x_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -175,7 +194,7 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) static void tc3589x_gpio_irq_mask(struct irq_data *d) { struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - tc3589x_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -185,7 +204,7 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d) static void tc3589x_gpio_irq_unmask(struct irq_data *d) { struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - tc3589x_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -222,8 +241,9 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = i * 8 + bit; + int virq = tc3589x_gpio_irq_get_virq(tc3589x_gpio, line); - handle_nested_irq(tc3589x_gpio->irq_base + line); + handle_nested_irq(virq); stat &= ~(1 << bit); } @@ -233,38 +253,60 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio) +static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) { - int base = tc3589x_gpio->irq_base; - int irq; + struct tc3589x *tc3589x_gpio = d->host_data; - for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { - irq_set_chip_data(irq, tc3589x_gpio); - irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, - handle_simple_irq); - irq_set_nested_thread(irq, 1); + irq_set_chip_data(virq, tc3589x_gpio); + irq_set_chip_and_handler(virq, &tc3589x_gpio_irq_chip, + handle_simple_irq); + irq_set_nested_thread(virq, 1); #ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); + set_irq_flags(virq, IRQF_VALID); #else - irq_set_noprobe(irq); + irq_set_noprobe(virq); #endif - } return 0; } -static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio) +static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) { - int base = tc3589x_gpio->irq_base; - int irq; - - for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { #ifdef CONFIG_ARM - set_irq_flags(irq, 0); + set_irq_flags(virq, 0); #endif - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); + irq_set_chip_and_handler(virq, NULL, NULL); + irq_set_chip_data(virq, NULL); +} + +static struct irq_domain_ops tc3589x_irq_ops = { + .map = tc3589x_gpio_irq_map, + .unmap = tc3589x_gpio_irq_unmap, + .xlate = irq_domain_xlate_twocell, +}; + +static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio) +{ + int base = tc3589x_gpio->irq_base; + + if (base) { + tc3589x_gpio->domain = irq_domain_add_legacy( + NULL, tc3589x_gpio->chip.ngpio, base, + 0, &tc3589x_irq_ops, tc3589x_gpio); } + else { + tc3589x_gpio->domain = irq_domain_add_linear( + NULL, tc3589x_gpio->chip.ngpio, + &tc3589x_irq_ops, tc3589x_gpio); + } + + if (!tc3589x_gpio->domain) { + dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n"); + return -ENOSYS; + } + + return 0; } static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) @@ -299,6 +341,9 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) tc3589x_gpio->irq_base = tc3589x->irq_base + TC3589x_INT_GPIO(0); + tc3589x_gpio->irq_base = tc3589x->irq_base ? + tc3589x->irq_base + TC3589x_INT_GPIO(0) : 0; + /* Bring the GPIO module out of reset */ ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_RSTCTRL_GPIRST, 0); @@ -313,7 +358,7 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) "tc3589x-gpio", tc3589x_gpio); if (ret) { dev_err(&pdev->dev, "unable to get irq: %d\n", ret); - goto out_removeirq; + goto out_free; } ret = gpiochip_add(&tc3589x_gpio->chip); @@ -331,8 +376,6 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) out_freeirq: free_irq(irq, tc3589x_gpio); -out_removeirq: - tc3589x_gpio_irq_remove(tc3589x_gpio); out_free: kfree(tc3589x_gpio); return ret; @@ -357,7 +400,6 @@ static int __devexit tc3589x_gpio_remove(struct platform_device *pdev) } free_irq(irq, tc3589x_gpio); - tc3589x_gpio_irq_remove(tc3589x_gpio); platform_set_drvdata(pdev, NULL); kfree(tc3589x_gpio);