From nobody Thu May 14 08:26:32 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 09526C433EF for ; Tue, 19 Apr 2022 14:29:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1353366AbiDSOb4 (ORCPT ); Tue, 19 Apr 2022 10:31:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46450 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1353320AbiDSObo (ORCPT ); Tue, 19 Apr 2022 10:31:44 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2354231342 for ; Tue, 19 Apr 2022 07:29:01 -0700 (PDT) Date: Tue, 19 Apr 2022 14:28:58 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1650378539; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fUcG/cHeHK2avOj5MIwspmxy4joi1MvGPD/smAa0W4k=; b=2i3g6CUPP//M7Ym/UglVuW7nezGcNnyoeEevSfiJsi5xcgx+LpEMM/5TKucF84gr3qgS2N 6HY7CAWlZZP/6GrdGGhwhMM8dgdn8LJ3odyfA5BJYCXxXZFkag5kE9FkwOmuEtn4Eecg9R nJJRv/dAITjpqVDlThe6k7RfPe7IGBsWjE/ydXUJ/WY+h+IaslRQeXfkdoYvjN9kI/XSMV F0sRIkz+wJ0h61UjNWWgmu5imXRSskhG3Lezdy+RzHpFyRIPcNvl20wCxmolux3x+ngD1s tHs9rzg235b5aeACWiJhbdDpBX0oPl8IO8CEUP5n4EdM2LkToWO/IwPCqWCqug== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1650378539; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fUcG/cHeHK2avOj5MIwspmxy4joi1MvGPD/smAa0W4k=; b=E9rvABNyDENKXTexvv/rRzUhTiGCtG5BCg2xWtookizocz6iT1bKdRAp6RbYJFszxiMXpz KWAI84demRfOZTAQ== From: "irqchip-bot for Marc Zyngier" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-kernel@vger.kernel.org Subject: [irqchip: irq/irqchip-next] Documentation: Update the recommended pattern for GPIO irqchips Cc: Andy Shevchenko , Bartosz Golaszewski , Marc Zyngier , tglx@linutronix.de In-Reply-To: <20220419141846.598305-11-maz@kernel.org> References: <20220419141846.598305-11-maz@kernel.org> MIME-Version: 1.0 Message-ID: <165037853825.4207.5139833137669251964.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The following commit has been merged into the irq/irqchip-next branch of ir= qchip: Commit-ID: 5644b66a9c63c3cadc6ba85faf5a15604e6cf29a Gitweb: https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-plat= forms/5644b66a9c63c3cadc6ba85faf5a15604e6cf29a Author: Marc Zyngier AuthorDate: Tue, 19 Apr 2022 15:18:46 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 19 Apr 2022 15:22:27 +01:00 Documentation: Update the recommended pattern for GPIO irqchips Update the documentation to get rid of the per-gpio_irq_chip irq_chip structure, and give examples of the new pattern. Reviewed-by: Andy Shevchenko Reviewed-by: Bartosz Golaszewski Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220419141846.598305-11-maz@kernel.org --- Documentation/driver-api/gpio/driver.rst | 175 +++++++++++++++++----- 1 file changed, 142 insertions(+), 33 deletions(-) diff --git a/Documentation/driver-api/gpio/driver.rst b/Documentation/drive= r-api/gpio/driver.rst index bbc5392..a1ddefa 100644 --- a/Documentation/driver-api/gpio/driver.rst +++ b/Documentation/driver-api/gpio/driver.rst @@ -417,30 +417,66 @@ struct gpio_irq_chip inside struct gpio_chip before a= dding the gpio_chip. If you do this, the additional irq_chip will be set up by gpiolib at the same time as setting up the rest of the GPIO functionality. The following is a typical example of a chained cascaded interrupt handler using -the gpio_irq_chip: +the gpio_irq_chip. Note how the mask/unmask (or disable/enable) functions +call into the core gpiolib code: =20 .. code-block:: c =20 - /* Typical state container with dynamic irqchip */ + /* Typical state container */ struct my_gpio { struct gpio_chip gc; - struct irq_chip irq; + }; + + static void my_gpio_mask_irq(struct irq_data *d) + { + struct gpio_chip *gc =3D irq_desc_get_handler_data(d); + + /* + * Perform any necessary action to mask the interrupt, + * and then call into the core code to synchronise the + * state. + */ + + gpiochip_disable_irq(gc, d->hwirq); + } + + static void my_gpio_unmask_irq(struct irq_data *d) + { + struct gpio_chip *gc =3D irq_desc_get_handler_data(d); + + gpiochip_enable_irq(gc, d->hwirq); + + /* + * Perform any necessary action to unmask the interrupt, + * after having called into the core code to synchronise + * the state. + */ + } + + /* + * Statically populate the irqchip. Note that it is made const + * (further indicated by the IRQCHIP_IMMUTABLE flag), and that + * the GPIOCHIP_IRQ_RESOURCE_HELPER macro adds some extra + * callbacks to the structure. + */ + static const struct irq_chip my_gpio_irq_chip =3D { + .name =3D "my_gpio_irq", + .irq_ack =3D my_gpio_ack_irq, + .irq_mask =3D my_gpio_mask_irq, + .irq_unmask =3D my_gpio_unmask_irq, + .irq_set_type =3D my_gpio_set_irq_type, + .flags =3D IRQCHIP_IMMUTABLE, + /* Provide the gpio resource callbacks */ + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; =20 int irq; /* from platform etc */ struct my_gpio *g; struct gpio_irq_chip *girq; =20 - /* Set up the irqchip dynamically */ - g->irq.name =3D "my_gpio_irq"; - g->irq.irq_ack =3D my_gpio_ack_irq; - g->irq.irq_mask =3D my_gpio_mask_irq; - g->irq.irq_unmask =3D my_gpio_unmask_irq; - g->irq.irq_set_type =3D my_gpio_set_irq_type; - /* Get a pointer to the gpio_irq_chip */ girq =3D &g->gc.irq; - girq->chip =3D &g->irq; + gpio_irq_chip_set_chip(girq, &my_gpio_irq_chip); girq->parent_handler =3D ftgpio_gpio_irq_handler; girq->num_parents =3D 1; girq->parents =3D devm_kcalloc(dev, 1, sizeof(*girq->parents), @@ -458,23 +494,58 @@ the interrupt separately and go with it: =20 .. code-block:: c =20 - /* Typical state container with dynamic irqchip */ + /* Typical state container */ struct my_gpio { struct gpio_chip gc; - struct irq_chip irq; + }; + + static void my_gpio_mask_irq(struct irq_data *d) + { + struct gpio_chip *gc =3D irq_desc_get_handler_data(d); + + /* + * Perform any necessary action to mask the interrupt, + * and then call into the core code to synchronise the + * state. + */ + + gpiochip_disable_irq(gc, d->hwirq); + } + + static void my_gpio_unmask_irq(struct irq_data *d) + { + struct gpio_chip *gc =3D irq_desc_get_handler_data(d); + + gpiochip_enable_irq(gc, d->hwirq); + + /* + * Perform any necessary action to unmask the interrupt, + * after having called into the core code to synchronise + * the state. + */ + } + + /* + * Statically populate the irqchip. Note that it is made const + * (further indicated by the IRQCHIP_IMMUTABLE flag), and that + * the GPIOCHIP_IRQ_RESOURCE_HELPER macro adds some extra + * callbacks to the structure. + */ + static const struct irq_chip my_gpio_irq_chip =3D { + .name =3D "my_gpio_irq", + .irq_ack =3D my_gpio_ack_irq, + .irq_mask =3D my_gpio_mask_irq, + .irq_unmask =3D my_gpio_unmask_irq, + .irq_set_type =3D my_gpio_set_irq_type, + .flags =3D IRQCHIP_IMMUTABLE, + /* Provide the gpio resource callbacks */ + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; =20 int irq; /* from platform etc */ struct my_gpio *g; struct gpio_irq_chip *girq; =20 - /* Set up the irqchip dynamically */ - g->irq.name =3D "my_gpio_irq"; - g->irq.irq_ack =3D my_gpio_ack_irq; - g->irq.irq_mask =3D my_gpio_mask_irq; - g->irq.irq_unmask =3D my_gpio_unmask_irq; - g->irq.irq_set_type =3D my_gpio_set_irq_type; - ret =3D devm_request_threaded_irq(dev, irq, NULL, irq_thread_fn, IRQF_ONESHOT, "my-chip", g); if (ret < 0) @@ -482,7 +553,7 @@ the interrupt separately and go with it: =20 /* Get a pointer to the gpio_irq_chip */ girq =3D &g->gc.irq; - girq->chip =3D &g->irq; + gpio_irq_chip_set_chip(girq, &my_gpio_irq_chip); /* This will let us handle the parent IRQ in the driver */ girq->parent_handler =3D NULL; girq->num_parents =3D 0; @@ -500,24 +571,61 @@ In this case the typical set-up will look like this: /* Typical state container with dynamic irqchip */ struct my_gpio { struct gpio_chip gc; - struct irq_chip irq; struct fwnode_handle *fwnode; }; =20 - int irq; /* from platform etc */ + static void my_gpio_mask_irq(struct irq_data *d) + { + struct gpio_chip *gc =3D irq_desc_get_handler_data(d); + + /* + * Perform any necessary action to mask the interrupt, + * and then call into the core code to synchronise the + * state. + */ + + gpiochip_disable_irq(gc, d->hwirq); + irq_mask_mask_parent(d); + } + + static void my_gpio_unmask_irq(struct irq_data *d) + { + struct gpio_chip *gc =3D irq_desc_get_handler_data(d); + + gpiochip_enable_irq(gc, d->hwirq); + + /* + * Perform any necessary action to unmask the interrupt, + * after having called into the core code to synchronise + * the state. + */ + + irq_mask_unmask_parent(d); + } + + /* + * Statically populate the irqchip. Note that it is made const + * (further indicated by the IRQCHIP_IMMUTABLE flag), and that + * the GPIOCHIP_IRQ_RESOURCE_HELPER macro adds some extra + * callbacks to the structure. + */ + static const struct irq_chip my_gpio_irq_chip =3D { + .name =3D "my_gpio_irq", + .irq_ack =3D my_gpio_ack_irq, + .irq_mask =3D my_gpio_mask_irq, + .irq_unmask =3D my_gpio_unmask_irq, + .irq_set_type =3D my_gpio_set_irq_type, + .flags =3D IRQCHIP_IMMUTABLE, + /* Provide the gpio resource callbacks */ + GPIOCHIP_IRQ_RESOURCE_HELPERS, + }; + struct my_gpio *g; struct gpio_irq_chip *girq; =20 - /* Set up the irqchip dynamically */ - g->irq.name =3D "my_gpio_irq"; - g->irq.irq_ack =3D my_gpio_ack_irq; - g->irq.irq_mask =3D my_gpio_mask_irq; - g->irq.irq_unmask =3D my_gpio_unmask_irq; - g->irq.irq_set_type =3D my_gpio_set_irq_type; - /* Get a pointer to the gpio_irq_chip */ girq =3D &g->gc.irq; - girq->chip =3D &g->irq; + gpio_irq_chip_set_chip(girq, &my_gpio_irq_chip); girq->default_type =3D IRQ_TYPE_NONE; girq->handler =3D handle_bad_irq; girq->fwnode =3D g->fwnode; @@ -605,8 +713,9 @@ When implementing an irqchip inside a GPIO driver, thes= e two functions should typically be called in the .irq_disable() and .irq_enable() callbacks from= the irqchip. =20 -When using the gpiolib irqchip helpers, these callbacks are automatically -assigned. +When IRQCHIP_IMMUTABLE is not advertised by the irqchip, these callbacks +are automatically assigned. This behaviour is deprecated and on its way +to be removed from the kernel. =20 =20 Real-Time compliance for GPIO IRQ chips