[{"id":1777061,"web_url":"http://patchwork.ozlabs.org/comment/1777061/","msgid":"<a3c7788e-7bf5-521d-88f1-c79713cf7354@ti.com>","list_archive_url":null,"date":"2017-09-28T14:22:41","subject":"Re: [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration","submitter":{"id":25084,"url":"http://patchwork.ozlabs.org/api/people/25084/","name":"Grygorii Strashko","email":"grygorii.strashko@ti.com"},"content":"On 09/28/2017 04:56 AM, Thierry Reding wrote:\n> From: Thierry Reding <treding@nvidia.com>\n> \n> Currently GPIO drivers are required to a GPIO chip and the corresponding\n> IRQ chip separately, which can result in a lot of boilerplate. Introduce\n> a new struct gpio_irq_chip, embedded in a struct gpio_chip, that drivers\n> can fill in if they want the GPIO core to automatically register the IRQ\n> chip associated with a GPIO chip.\n> \n> Signed-off-by: Thierry Reding <treding@nvidia.com>\n> ---\n>   drivers/gpio/gpiolib.c      | 146 +++++++++++++++++++++++++++++++++++++++++++-\n>   include/linux/gpio/driver.h |  64 +++++++++++++++++++\n>   2 files changed, 207 insertions(+), 3 deletions(-)\n> \n> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c\n> index eb80dac4e26a..b34d9cbd5809 100644\n> --- a/drivers/gpio/gpiolib.c\n> +++ b/drivers/gpio/gpiolib.c\n> @@ -72,6 +72,7 @@ static LIST_HEAD(gpio_lookup_list);\n>   LIST_HEAD(gpio_devices);\n>   \n>   static void gpiochip_free_hogs(struct gpio_chip *chip);\n> +static int gpiochip_add_irqchip(struct gpio_chip *gpiochip);\n>   static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);\n>   static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip);\n>   static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip);\n> @@ -1260,6 +1261,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)\n>   \tif (status)\n>   \t\tgoto err_remove_from_list;\n>   \n> +\tstatus = gpiochip_add_irqchip(chip);\n> +\tif (status)\n> +\t\tgoto err_remove_chip;\n> +\n>   \tstatus = of_gpiochip_add(chip);\n>   \tif (status)\n>   \t\tgoto err_remove_chip;\n> @@ -1626,8 +1631,8 @@ EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);\n>    * gpiochip by assigning the gpiochip as chip data, and using the irqchip\n>    * stored inside the gpiochip.\n>    */\n> -static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,\n> -\t\t\t    irq_hw_number_t hwirq)\n> +int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,\n> +\t\t     irq_hw_number_t hwirq)\n>   {\n>   \tstruct gpio_chip *chip = d->host_data;\n>   \n> @@ -1655,8 +1660,9 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,\n>   \n>   \treturn 0;\n>   }\n> +EXPORT_SYMBOL_GPL(gpiochip_irq_map);\n>   \n> -static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)\n> +void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)\n>   {\n>   \tstruct gpio_chip *chip = d->host_data;\n>   \n> @@ -1665,6 +1671,7 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)\n>   \tirq_set_chip_and_handler(irq, NULL, NULL);\n>   \tirq_set_chip_data(irq, NULL);\n>   }\n> +EXPORT_SYMBOL_GPL(gpiochip_irq_unmap);\n>   \n>   static const struct irq_domain_ops gpiochip_domain_ops = {\n>   \t.map\t= gpiochip_irq_map,\n> @@ -1705,6 +1712,124 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)\n>   \treturn irq_create_mapping(chip->irqdomain, offset);\n>   }\n>   \n> +/**\n> + * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip\n> + * @gpiochip: the GPIO chip to add the IRQ chip to\n> + */\n> +static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)\n> +{\n> +\tstruct irq_chip *irqchip = gpiochip->irqchip;\n> +\tconst struct irq_domain_ops *ops;\n> +\tstruct device_node *np;\n> +\tunsigned int type;\n> +\tunsigned int i;\n> +\n> +\tif (!irqchip)\n> +\t\treturn 0;\n> +\n> +\tif (gpiochip->irq.parent_handler && gpiochip->can_sleep) {\n> +\t\tchip_err(gpiochip, \"you cannot have chained interrupts on a \"\n> +\t\t\t \"chip that may sleep\\n\");\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\ttype = gpiochip->irq_default_type;\n> +\tnp = gpiochip->parent->of_node;\n> +\n> +#ifdef CONFIG_OF_GPIO\n> +\t/*\n> +\t * If the gpiochip has an assigned OF node this takes precedence\n> +\t * FIXME: get rid of this and use gpiochip->parent->of_node\n> +\t * everywhere\n> +\t */\n> +\tif (gpiochip->of_node)\n> +\t\tnp = gpiochip->of_node;\n> +#endif\n> +\n> +\t/*\n> +\t * Specifying a default trigger is a terrible idea if DT or ACPI is\n> +\t * used to configure the interrupts, as you may end up with\n> +\t * conflicting triggers. Tell the user, and reset to NONE.\n> +\t */\n> +\tif (WARN(np && type != IRQ_TYPE_NONE,\n> +\t\t \"%s: Ignoring %u default trigger\\n\", np->full_name, type))\n> +\t\ttype = IRQ_TYPE_NONE;\n> +\n> +\tif (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) {\n> +\t\tacpi_handle_warn(ACPI_HANDLE(gpiochip->parent),\n> +\t\t\t\t \"Ignoring %u default trigger\\n\", type);\n> +\t\ttype = IRQ_TYPE_NONE;\n> +\t}\n> +\n> +\tgpiochip->to_irq = gpiochip_to_irq;\n> +\tgpiochip->irq_default_type = type;\n> +\n> +\tif (gpiochip->irq.domain_ops)\n> +\t\tops = gpiochip->irq.domain_ops;\n> +\telse\n> +\t\tops = &gpiochip_domain_ops;\n> +\n> +\tgpiochip->irqdomain = irq_domain_add_simple(np, gpiochip->ngpio,\n> +\t\t\t\t\t\t    gpiochip->irq_base,\n> +\t\t\t\t\t\t    ops, gpiochip);\n> +\tif (!gpiochip->irqdomain)\n> +\t\treturn -EINVAL;\n> +\n> +\t/*\n> +\t * It is possible for a driver to override this, but only if the\n> +\t * alternative functions are both implemented.\n> +\t */\n> +\tif (!irqchip->irq_request_resources &&\n> +\t    !irqchip->irq_release_resources) {\n> +\t\tirqchip->irq_request_resources = gpiochip_irq_reqres;\n> +\t\tirqchip->irq_release_resources = gpiochip_irq_relres;\n> +\t}\n> +\n> +\tif (gpiochip->irq.parent_handler) {\n> +\t\tvoid *data = gpiochip->irq.parent_handler_data ?: gpiochip;\n> +\n> +\t\tfor (i = 0; i < gpiochip->irq.num_parents; i++) {\n> +\t\t\t/*\n> +\t\t\t * The parent IRQ chip is already using the chip_data\n> +\t\t\t * for this IRQ chip, so our callbacks simply use the\n> +\t\t\t * handler_data.\n> +\t\t\t */\n> +\t\t\tirq_set_chained_handler_and_data(gpiochip->irq.parents[i],\n> +\t\t\t\t\t\t\t gpiochip->irq.parent_handler,\n> +\t\t\t\t\t\t\t data);\n> +\t\t}\n> +\n> +\t\tgpiochip->irq_nested = false;\n> +\t} else {\n> +\t\tgpiochip->irq_nested = true;\n> +\t}\n> +\n> +\t/*\n> +\t * Prepare the mapping since the IRQ chip shall be orthogonal to any\n> +\t * GPIO chip calls.\n> +\t */\n> +\tfor (i = 0; i < gpiochip->ngpio; i++) {\n> +\t\tunsigned int irq;\n> +\n> +\t\tif (!gpiochip_irqchip_irq_valid(gpiochip, i))\n> +\t\t\tcontinue;\n> +\n> +\t\tirq = irq_create_mapping(gpiochip->irqdomain, i);\n> +\t\tif (!irq) {\n> +\t\t\tchip_err(gpiochip,\n> +\t\t\t\t \"failed to create IRQ mapping for GPIO#%u\\n\",\n> +\t\t\t\t i);\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\tirq_set_parent(irq, gpiochip->irq.map[i]);\n\nIRQs should be mapped dynamically.\nPls, see commit dc749a0 \"gpiolib: allow gpio irqchip to map irqs dynamically\"\n\n> +\t}\n> +\n> +\tacpi_gpiochip_request_interrupts(gpiochip);\n> +\n> +\treturn 0;\n> +}\n> +\n>   /**\n>    * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip\n>    * @gpiochip: the gpiochip to remove the irqchip from\n> @@ -1722,6 +1847,16 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)\n>   \t\tirq_set_handler_data(gpiochip->irq_chained_parent, NULL);\n>   \t}\n>   \n> +\tif (gpiochip->irqchip) {\n> +\t\tstruct gpio_irq_chip *irq = &gpiochip->irq;\n> +\t\tunsigned int i;\n> +\n> +\t\tfor (i = 0; i < irq->num_parents; i++) {\n> +\t\t\tirq_set_chained_handler(irq->parents[i], NULL);\n> +\t\t\tirq_set_handler_data(irq->parents[i], NULL);\n> +\t\t}\n> +\t}\n> +\n>   \t/* Remove all IRQ mappings and delete the domain */\n>   \tif (gpiochip->irqdomain) {\n>   \t\tfor (offset = 0; offset < gpiochip->ngpio; offset++) {\n> @@ -1842,6 +1977,11 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);\n>   \n>   #else /* CONFIG_GPIOLIB_IRQCHIP */\n>   \n> +static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)\n> +{\n> +\treturn 0;\n> +}\n> +\n>   static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}\n>   static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)\n>   {\n> diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h\n> index c97f8325e8bf..6100b171817e 100644\n> --- a/include/linux/gpio/driver.h\n> +++ b/include/linux/gpio/driver.h\n> @@ -19,6 +19,58 @@ struct module;\n>   \n>   #ifdef CONFIG_GPIOLIB\n>   \n> +#ifdef CONFIG_GPIOLIB_IRQCHIP\n> +/**\n> + * struct gpio_irq_chip - GPIO interrupt controller\n> + */\n> +struct gpio_irq_chip {\n> +\t/**\n> +\t * @domain_ops:\n> +\t *\n> +\t * Table of interrupt domain operations for this IRQ chip.\n> +\t */\n> +\tconst struct irq_domain_ops *domain_ops;\n> +\n> +\t/**\n> +\t * @parent_handler:\n> +\t *\n> +\t * The interrupt handler for the GPIO chip's parent interrupts, may be\n> +\t * NULL if the parent interrupts are nested rather than cascaded.\n> +\t */\n> +\tirq_flow_handler_t parent_handler;\n> +\n> +\t/**\n> +\t * @parent_handler_data:\n> +\t *\n> +\t * Data associated, and passed to, the handler for the parent\n> +\t * interrupt.\n> +\t */\n> +\tvoid *parent_handler_data;\n> +\n> +\t/**\n> +\t * @num_parents:\n> +\t *\n> +\t * The number of interrupt parents of a GPIO chip.\n> +\t */\n> +\tunsigned int num_parents;\n> +\n> +\t/**\n> +\t * @parents:\n> +\t *\n> +\t * A list of interrupt parents of a GPIO chip. This is owned by the\n> +\t * driver, so the core will only reference this list, not modify it.\n> +\t */\n> +\tunsigned int *parents;\n> +\n> +\t/**\n> +\t * @map:\n> +\t *\n> +\t * A list of interrupt parents for each line of a GPIO chip.\n> +\t */\n> +\tunsigned int *map;\n> +};\n> +#endif\n> +\n>   /**\n>    * struct gpio_chip - abstract a GPIO controller\n>    * @label: a functional name for the GPIO device, such as a part\n> @@ -173,6 +225,14 @@ struct gpio_chip {\n>   \tbool\t\t\tirq_need_valid_mask;\n>   \tunsigned long\t\t*irq_valid_mask;\n>   \tstruct lock_class_key\t*lock_key;\n> +\n> +\t/**\n> +\t * @irq:\n> +\t *\n> +\t * Integrates interrupt chip functionality with the GPIO chip. Can be\n> +\t * used to handle IRQs for most practical cases.\n> +\t */\n> +\tstruct gpio_irq_chip irq;\n>   #endif\n>   \n>   #if defined(CONFIG_OF_GPIO)\n> @@ -264,6 +324,10 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,\n>   \n>   #ifdef CONFIG_GPIOLIB_IRQCHIP\n>   \n> +int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,\n> +\t\t     irq_hw_number_t hwirq);\n> +void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq);\n> +\n>   void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,\n>   \t\tstruct irq_chip *irqchip,\n>   \t\tunsigned int parent_irq,\n>","headers":{"Return-Path":"<linux-gpio-owner@vger.kernel.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=linux-gpio-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ti.com header.i=@ti.com header.b=\"qqn0iUUN\";\n\tdkim-atps=neutral"],"Received":["from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3y2xjf4x6Vz9t5x\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 29 Sep 2017 00:22:46 +1000 (AEST)","(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1752156AbdI1OWo (ORCPT <rfc822;incoming@patchwork.ozlabs.org>);\n\tThu, 28 Sep 2017 10:22:44 -0400","from lelnx194.ext.ti.com ([198.47.27.80]:51942 \"EHLO\n\tlelnx194.ext.ti.com\" rhost-flags-OK-OK-OK-OK) by vger.kernel.org\n\twith ESMTP id S1752017AbdI1OWn (ORCPT\n\t<rfc822; linux-gpio@vger.kernel.org>); Thu, 28 Sep 2017 10:22:43 -0400","from dflxv15.itg.ti.com ([128.247.5.124])\n\tby lelnx194.ext.ti.com (8.15.1/8.15.1) with ESMTP id v8SEMf1E002627; \n\tThu, 28 Sep 2017 09:22:41 -0500","from DLEE70.ent.ti.com (dlemailx.itg.ti.com [157.170.170.113])\n\tby dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id v8SEMf8F016802;\n\tThu, 28 Sep 2017 09:22:41 -0500","from [128.247.59.147] (128.247.59.147) by DLEE70.ent.ti.com\n\t(157.170.170.113) with Microsoft SMTP Server id 14.3.294.0;\n\tThu, 28 Sep 2017 09:22:41 -0500"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ti.com;\n\ts=ti-com-17Q1; t=1506608561;\n\tbh=/3k6MUyAlXWkYWmLpJgLrF2+d/ZyzH5WPsTaTFAcVDs=;\n\th=Subject:To:CC:References:From:Date:In-Reply-To;\n\tb=qqn0iUUNClzl7Ky1M21uU7bvy3hujQ4QxAExtF2S8sw5AY2EoFsAoAfXz5w7GCUw3\n\t7G6hU9eQvMl8qkkAc9P3t9XoByqn/1HCFaV5PfCMZIF71ZE81e/u8hdF2SQvufbEHP\n\tnzOqY9EnvDiy2Pyc63kAxQtynUeRQBz2/wJutCFY=","Subject":"Re: [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration","To":"Thierry Reding <thierry.reding@gmail.com>,\n\tLinus Walleij <linus.walleij@linaro.org>","CC":"Jonathan Hunter <jonathanh@nvidia.com>,\n\t<linux-gpio@vger.kernel.org>, <linux-tegra@vger.kernel.org>,\n\t<linux-kernel@vger.kernel.org>","References":"<20170928095628.21966-1-thierry.reding@gmail.com>\n\t<20170928095628.21966-2-thierry.reding@gmail.com>","From":"Grygorii Strashko <grygorii.strashko@ti.com>","Message-ID":"<a3c7788e-7bf5-521d-88f1-c79713cf7354@ti.com>","Date":"Thu, 28 Sep 2017 09:22:41 -0500","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101\n\tThunderbird/52.3.0","MIME-Version":"1.0","In-Reply-To":"<20170928095628.21966-2-thierry.reding@gmail.com>","Content-Type":"text/plain; charset=\"utf-8\"","Content-Language":"en-US","Content-Transfer-Encoding":"7bit","X-Originating-IP":"[128.247.59.147]","Sender":"linux-gpio-owner@vger.kernel.org","Precedence":"bulk","List-ID":"<linux-gpio.vger.kernel.org>","X-Mailing-List":"linux-gpio@vger.kernel.org"}},{"id":1784200,"web_url":"http://patchwork.ozlabs.org/comment/1784200/","msgid":"<2701b79e-8d96-5805-c9b0-b779ab11757e@ti.com>","list_archive_url":null,"date":"2017-10-10T22:56:27","subject":"Re: [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration","submitter":{"id":25084,"url":"http://patchwork.ozlabs.org/api/people/25084/","name":"Grygorii Strashko","email":"grygorii.strashko@ti.com"},"content":"On 09/28/2017 04:56 AM, Thierry Reding wrote:\n> From: Thierry Reding <treding@nvidia.com>\n> \n> Currently GPIO drivers are required to a GPIO chip and the corresponding\n> IRQ chip separately, which can result in a lot of boilerplate. Introduce\n> a new struct gpio_irq_chip, embedded in a struct gpio_chip, that drivers\n> can fill in if they want the GPIO core to automatically register the IRQ\n> chip associated with a GPIO chip.\n\nfew more comments.\n> \n> Signed-off-by: Thierry Reding <treding@nvidia.com>\n> ---\n>   drivers/gpio/gpiolib.c      | 146 +++++++++++++++++++++++++++++++++++++++++++-\n>   include/linux/gpio/driver.h |  64 +++++++++++++++++++\n>   2 files changed, 207 insertions(+), 3 deletions(-)\n> \n> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c\n> index eb80dac4e26a..b34d9cbd5809 100644\n> --- a/drivers/gpio/gpiolib.c\n> +++ b/drivers/gpio/gpiolib.c\n> @@ -72,6 +72,7 @@ static LIST_HEAD(gpio_lookup_list);\n>   LIST_HEAD(gpio_devices);\n>   \n>   static void gpiochip_free_hogs(struct gpio_chip *chip);\n> +static int gpiochip_add_irqchip(struct gpio_chip *gpiochip);\n>   static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);\n>   static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip);\n>   static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip);\n> @@ -1260,6 +1261,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)\n>   \tif (status)\n>   \t\tgoto err_remove_from_list;\n>   \n> +\tstatus = gpiochip_add_irqchip(chip);\n> +\tif (status)\n> +\t\tgoto err_remove_chip;\n> +\n\nlock_key - it better if drivers will not need to define it.\n\n>   \tstatus = of_gpiochip_add(chip);\n>   \tif (status)\n>   \t\tgoto err_remove_chip;\n> @@ -1626,8 +1631,8 @@ EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);\n>    * gpiochip by assigning the gpiochip as chip data, and using the irqchip\n>    * stored inside the gpiochip.\n>    */\n> -static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,\n> -\t\t\t    irq_hw_number_t hwirq)\n> +int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,\n> +\t\t     irq_hw_number_t hwirq)\n>   {\n>   \tstruct gpio_chip *chip = d->host_data;\n>   \n> @@ -1655,8 +1660,9 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,\n>   \n>   \treturn 0;\n>   }\n> +EXPORT_SYMBOL_GPL(gpiochip_irq_map);\n>   \n> -static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)\n> +void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)\n>   {\n>   \tstruct gpio_chip *chip = d->host_data;\n>   \n> @@ -1665,6 +1671,7 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)\n>   \tirq_set_chip_and_handler(irq, NULL, NULL);\n>   \tirq_set_chip_data(irq, NULL);\n>   }\n> +EXPORT_SYMBOL_GPL(gpiochip_irq_unmap);\n>   \n>   static const struct irq_domain_ops gpiochip_domain_ops = {\n>   \t.map\t= gpiochip_irq_map,\n> @@ -1705,6 +1712,124 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)\n>   \treturn irq_create_mapping(chip->irqdomain, offset);\n>   }\n>   \n> +/**\n> + * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip\n> + * @gpiochip: the GPIO chip to add the IRQ chip to\n> + */\n> +static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)\n> +{\n> +\tstruct irq_chip *irqchip = gpiochip->irqchip;\n> +\tconst struct irq_domain_ops *ops;\n> +\tstruct device_node *np;\n> +\tunsigned int type;\n> +\tunsigned int i;\n> +\n> +\tif (!irqchip)\n> +\t\treturn 0;\n> +\n> +\tif (gpiochip->irq.parent_handler && gpiochip->can_sleep) {\n> +\t\tchip_err(gpiochip, \"you cannot have chained interrupts on a \"\n> +\t\t\t \"chip that may sleep\\n\");\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\ttype = gpiochip->irq_default_type;\n> +\tnp = gpiochip->parent->of_node;\n> +\n> +#ifdef CONFIG_OF_GPIO\n> +\t/*\n> +\t * If the gpiochip has an assigned OF node this takes precedence\n> +\t * FIXME: get rid of this and use gpiochip->parent->of_node\n> +\t * everywhere\n> +\t */\n> +\tif (gpiochip->of_node)\n> +\t\tnp = gpiochip->of_node;\n> +#endif\n\nabove can be retrieved from gpio_chip->gpiodev\n\n> +\n> +\t/*\n> +\t * Specifying a default trigger is a terrible idea if DT or ACPI is\n> +\t * used to configure the interrupts, as you may end up with\n> +\t * conflicting triggers. Tell the user, and reset to NONE.\n> +\t */\n> +\tif (WARN(np && type != IRQ_TYPE_NONE,\n> +\t\t \"%s: Ignoring %u default trigger\\n\", np->full_name, type))\n> +\t\ttype = IRQ_TYPE_NONE;\n> +\n> +\tif (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) {\n> +\t\tacpi_handle_warn(ACPI_HANDLE(gpiochip->parent),\n> +\t\t\t\t \"Ignoring %u default trigger\\n\", type);\n> +\t\ttype = IRQ_TYPE_NONE;\n> +\t}\n> +\n> +\tgpiochip->to_irq = gpiochip_to_irq;\n> +\tgpiochip->irq_default_type = type;\n> +\n> +\tif (gpiochip->irq.domain_ops)\n> +\t\tops = gpiochip->irq.domain_ops;\n> +\telse\n> +\t\tops = &gpiochip_domain_ops;\n> +\n> +\tgpiochip->irqdomain = irq_domain_add_simple(np, gpiochip->ngpio,\n> +\t\t\t\t\t\t    gpiochip->irq_base,\n> +\t\t\t\t\t\t    ops, gpiochip);\n> +\tif (!gpiochip->irqdomain)\n> +\t\treturn -EINVAL;\n> +\n> +\t/*\n> +\t * It is possible for a driver to override this, but only if the\n> +\t * alternative functions are both implemented.\n> +\t */\n> +\tif (!irqchip->irq_request_resources &&\n> +\t    !irqchip->irq_release_resources) {\n> +\t\tirqchip->irq_request_resources = gpiochip_irq_reqres;\n> +\t\tirqchip->irq_release_resources = gpiochip_irq_relres;\n> +\t}\n> +\n> +\tif (gpiochip->irq.parent_handler) {\n> +\t\tvoid *data = gpiochip->irq.parent_handler_data ?: gpiochip;\n> +\n> +\t\tfor (i = 0; i < gpiochip->irq.num_parents; i++) {\n> +\t\t\t/*\n> +\t\t\t * The parent IRQ chip is already using the chip_data\n> +\t\t\t * for this IRQ chip, so our callbacks simply use the\n> +\t\t\t * handler_data.\n> +\t\t\t */\n> +\t\t\tirq_set_chained_handler_and_data(gpiochip->irq.parents[i],\n> +\t\t\t\t\t\t\t gpiochip->irq.parent_handler,\n> +\t\t\t\t\t\t\t data);\n> +\t\t}\n> +\n> +\t\tgpiochip->irq_nested = false;\n> +\t} else {\n> +\t\tgpiochip->irq_nested = true;\n\nGPIO driver might not specify parent_handler, but it doesn't mean it's irq_nested,\nas driver may use request_irq()\n\n> +\t}\n> +\n> +\t/*\n> +\t * Prepare the mapping since the IRQ chip shall be orthogonal to any\n> +\t * GPIO chip calls.\n> +\t */\n> +\tfor (i = 0; i < gpiochip->ngpio; i++) {\n> +\t\tunsigned int irq;\n> +\n> +\t\tif (!gpiochip_irqchip_irq_valid(gpiochip, i))\n> +\t\t\tcontinue;\n> +\n> +\t\tirq = irq_create_mapping(gpiochip->irqdomain, i);\n> +\t\tif (!irq) {\n> +\t\t\tchip_err(gpiochip,\n> +\t\t\t\t \"failed to create IRQ mapping for GPIO#%u\\n\",\n> +\t\t\t\t i);\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\tirq_set_parent(irq, gpiochip->irq.map[i]);\n> +\t}\n> +\n> +\tacpi_gpiochip_request_interrupts(gpiochip);\n> +\n> +\treturn 0;\n> +}\n> +\n>   /**\n>    * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip\n>    * @gpiochip: the gpiochip to remove the irqchip from\n> @@ -1722,6 +1847,16 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)\n>   \t\tirq_set_handler_data(gpiochip->irq_chained_parent, NULL);\n>   \t}\n>   \n> +\tif (gpiochip->irqchip) {\n> +\t\tstruct gpio_irq_chip *irq = &gpiochip->irq;\n> +\t\tunsigned int i;\n> +\n> +\t\tfor (i = 0; i < irq->num_parents; i++) {\n> +\t\t\tirq_set_chained_handler(irq->parents[i], NULL);\n> +\t\t\tirq_set_handler_data(irq->parents[i], NULL);\n> +\t\t}\n> +\t}\n> +\n>   \t/* Remove all IRQ mappings and delete the domain */\n>   \tif (gpiochip->irqdomain) {\n>   \t\tfor (offset = 0; offset < gpiochip->ngpio; offset++) {\n> @@ -1842,6 +1977,11 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);\n>   \n>   #else /* CONFIG_GPIOLIB_IRQCHIP */\n>   \n> +static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)\n> +{\n> +\treturn 0;\n> +}\n> +\n>   static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}\n>   static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)\n>   {\n> diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h\n> index c97f8325e8bf..6100b171817e 100644\n> --- a/include/linux/gpio/driver.h\n> +++ b/include/linux/gpio/driver.h\n> @@ -19,6 +19,58 @@ struct module;\n>   \n>   #ifdef CONFIG_GPIOLIB\n>   \n> +#ifdef CONFIG_GPIOLIB_IRQCHIP\n> +/**\n> + * struct gpio_irq_chip - GPIO interrupt controller\n> + */\n> +struct gpio_irq_chip {\n> +\t/**\n> +\t * @domain_ops:\n> +\t *\n> +\t * Table of interrupt domain operations for this IRQ chip.\n> +\t */\n> +\tconst struct irq_domain_ops *domain_ops;\n> +\n> +\t/**\n> +\t * @parent_handler:\n> +\t *\n> +\t * The interrupt handler for the GPIO chip's parent interrupts, may be\n> +\t * NULL if the parent interrupts are nested rather than cascaded.\n> +\t */\n> +\tirq_flow_handler_t parent_handler;\n> +\n> +\t/**\n> +\t * @parent_handler_data:\n> +\t *\n> +\t * Data associated, and passed to, the handler for the parent\n> +\t * interrupt.\n> +\t */\n> +\tvoid *parent_handler_data;\n> +\n> +\t/**\n> +\t * @num_parents:\n> +\t *\n> +\t * The number of interrupt parents of a GPIO chip.\n> +\t */\n> +\tunsigned int num_parents;\n> +\n> +\t/**\n> +\t * @parents:\n> +\t *\n> +\t * A list of interrupt parents of a GPIO chip. This is owned by the\n> +\t * driver, so the core will only reference this list, not modify it.\n> +\t */\n> +\tunsigned int *parents;\n> +\n> +\t/**\n> +\t * @map:\n> +\t *\n> +\t * A list of interrupt parents for each line of a GPIO chip.\n> +\t */\n> +\tunsigned int *map;\n> +};\n> +#endif\n> +\n>   /**\n>    * struct gpio_chip - abstract a GPIO controller\n>    * @label: a functional name for the GPIO device, such as a part\n> @@ -173,6 +225,14 @@ struct gpio_chip {\n>   \tbool\t\t\tirq_need_valid_mask;\n>   \tunsigned long\t\t*irq_valid_mask;\n>   \tstruct lock_class_key\t*lock_key;\n> +\n> +\t/**\n> +\t * @irq:\n> +\t *\n> +\t * Integrates interrupt chip functionality with the GPIO chip. Can be\n> +\t * used to handle IRQs for most practical cases.\n> +\t */\n> +\tstruct gpio_irq_chip irq;\n>   #endif\n>   \n>   #if defined(CONFIG_OF_GPIO)\n> @@ -264,6 +324,10 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,\n>   \n>   #ifdef CONFIG_GPIOLIB_IRQCHIP\n>   \n> +int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,\n> +\t\t     irq_hw_number_t hwirq);\n> +void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq);\n> +\n>   void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,\n>   \t\tstruct irq_chip *irqchip,\n>   \t\tunsigned int parent_irq,\n>","headers":{"Return-Path":"<linux-gpio-owner@vger.kernel.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=linux-gpio-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ti.com header.i=@ti.com header.b=\"n4d9MUFD\";\n\tdkim-atps=neutral"],"Received":["from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3yBXYp6TZxz9t6C\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 11 Oct 2017 09:57:18 +1100 (AEDT)","(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1756551AbdJJW5R (ORCPT <rfc822;incoming@patchwork.ozlabs.org>);\n\tTue, 10 Oct 2017 18:57:17 -0400","from fllnx209.ext.ti.com ([198.47.19.16]:54967 \"EHLO\n\tfllnx209.ext.ti.com\" rhost-flags-OK-OK-OK-OK) by vger.kernel.org\n\twith ESMTP id S1756299AbdJJW5Q (ORCPT\n\t<rfc822; linux-gpio@vger.kernel.org>); Tue, 10 Oct 2017 18:57:16 -0400","from dflxv15.itg.ti.com ([128.247.5.124])\n\tby fllnx209.ext.ti.com (8.15.1/8.15.1) with ESMTP id v9AMuWC3013811; \n\tTue, 10 Oct 2017 17:56:32 -0500","from DLEE70.ent.ti.com (dlee70.ent.ti.com [157.170.170.113])\n\tby dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id v9AMuRoE025128;\n\tTue, 10 Oct 2017 17:56:27 -0500","from [128.247.59.147] (128.247.59.147) by DLEE70.ent.ti.com\n\t(157.170.170.113) with Microsoft SMTP Server id 14.3.294.0;\n\tTue, 10 Oct 2017 17:56:26 -0500"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ti.com;\n\ts=ti-com-17Q1; t=1507676192;\n\tbh=tb2JVzXZaBQ6LBkTE9M75xjq/2fCNo2OAJTfY9+lQN4=;\n\th=Subject:To:CC:References:From:Date:In-Reply-To;\n\tb=n4d9MUFDlNtweGQlghZ9MfbgtQXbQpHEh+lGFFqtsn3k9bJqmm43Iqx7mC2IFVdsq\n\ttFJxRHrNwNuVeFFOW/jy7kG83kFfcdV0Bin1u3+aUHoID3iBbsGvI5d+tX1+i5TnFy\n\tV+WIAIevDCe99ziX+sGADmV+foeshfzu+OhAaTYI=","Subject":"Re: [PATCH v2 01/16] gpio: Implement tighter IRQ chip integration","To":"Thierry Reding <thierry.reding@gmail.com>,\n\tLinus Walleij <linus.walleij@linaro.org>","CC":"Jonathan Hunter <jonathanh@nvidia.com>,\n\t<linux-gpio@vger.kernel.org>, <linux-tegra@vger.kernel.org>,\n\t<linux-kernel@vger.kernel.org>","References":"<20170928095628.21966-1-thierry.reding@gmail.com>\n\t<20170928095628.21966-2-thierry.reding@gmail.com>","From":"Grygorii Strashko <grygorii.strashko@ti.com>","Message-ID":"<2701b79e-8d96-5805-c9b0-b779ab11757e@ti.com>","Date":"Tue, 10 Oct 2017 17:56:27 -0500","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101\n\tThunderbird/52.3.0","MIME-Version":"1.0","In-Reply-To":"<20170928095628.21966-2-thierry.reding@gmail.com>","Content-Type":"text/plain; charset=\"utf-8\"","Content-Language":"en-US","Content-Transfer-Encoding":"7bit","X-Originating-IP":"[128.247.59.147]","Sender":"linux-gpio-owner@vger.kernel.org","Precedence":"bulk","List-ID":"<linux-gpio.vger.kernel.org>","X-Mailing-List":"linux-gpio@vger.kernel.org"}}]