From nobody Tue Jun 30 06:33:57 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 EDB5CC433EF for ; Mon, 24 Jan 2022 09:57:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236799AbiAXJ5G (ORCPT ); Mon, 24 Jan 2022 04:57:06 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57934 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232102AbiAXJ5F (ORCPT ); Mon, 24 Jan 2022 04:57:05 -0500 Received: from mail-lf1-x134.google.com (mail-lf1-x134.google.com [IPv6:2a00:1450:4864:20::134]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A71E7C06173B for ; Mon, 24 Jan 2022 01:57:04 -0800 (PST) Received: by mail-lf1-x134.google.com with SMTP id u14so17030835lfo.11 for ; Mon, 24 Jan 2022 01:57:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cogentembedded-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=8mRHPmf3OxMEiqwldr9U0jRCGBgB7i4RBCLVtBo3jEo=; b=MBkP4wug/JG2vURr8jzf9hhOtL6gnueQCI3P6yqRlnOHR7q/+YCFPRUuWb7iy49Geh 5FpZzkE3ITYyA6j1fYuD5XC7hw8vX1FLE3Yp4+0FbEOGKxCW+kyHWF0iaiaYc9/HQBJk fCWyZTTRMpm/0nA3K9dTrqbLOS+SAoX8YuS6AvAfnMHT5aQdtQ5jggKsbpJp0hPkKkKV wokoj4K5FJl0p/WsCgF6ef/y8cHG4t6YVS+g6Ebn3OLF3Frs3ARdtr7I7Bb8A267sF2m 9T6l26t5VoRLtjSxsBLw827S+n5fFHyPnVvcHx69W0GtEkIam40ZhlCSsxfTWYtxmkZw vHUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=8mRHPmf3OxMEiqwldr9U0jRCGBgB7i4RBCLVtBo3jEo=; b=62eJllzeWJVZwyIY4566ImSLXPpdXxvxRBdl6AEvPz7O6Cr4fh3Kc9IGfLB5h1iYhp SzDUaE/kY4amZHUWp4nuErI0j9RlXUE1zWCnNPZPdo2LeoBsWbiEr1RciJuZfX+xFALn T5FtSrnTo5My0u+CwSGfne1Qk5sXCZRJGh9j/gpmxnWIjoHjgJWH7uW2fO5Fgu/c5nHU zvVqDEZ2F/mViARpOO6V58sHhzhO9GL5udw4ENMJ8Hg5UKnxMoASvtNXG6ixsD/JiL1r i2UwYwCoBDTQw+g2Q/sDE9RAJa69/SazcBFYEvHehyh701bWTIkyb7f8LAlMc7dMt/2Q qQ3g== X-Gm-Message-State: AOAM530AQLkEZsyqVN7wV6eDgFS0FjszkgjJJwDbTadD+tmw7YcImfZG OemcKCpXBEfLNrfGfCrn3CKUfIorYtQvmtsx X-Google-Smtp-Source: ABdhPJwEMkxgr5H2YNVgmD1rmpvC+ppZ9HwaYUz4w0Yx4mdawRm68IyM3yLnXcqh7LS7UBk3UyKtcQ== X-Received: by 2002:a05:6512:1103:: with SMTP id l3mr2509754lfg.680.1643018223004; Mon, 24 Jan 2022 01:57:03 -0800 (PST) Received: from cobook.home (nikaet.starlink.ru. [94.141.168.29]) by smtp.gmail.com with ESMTPSA id e10sm857952ljk.30.2022.01.24.01.57.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Jan 2022 01:57:02 -0800 (PST) From: Nikita Yushchenko To: Thomas Gleixner , Marc Zyngier , Geert Uytterhoeven , Eugeniu Rosca Cc: linux-kernel@vger.kernel.org, Nikita Yushchenko Subject: [PATCH v2] drivers: irqchip: add irq-type-changer Date: Mon, 24 Jan 2022 12:56:52 +0300 Message-Id: <20220124095652.522099-1-nikita.yoush@cogentembedded.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Irq type changer is a virtual irqchip useful to support boards that change (e.g. invert) interrupt signal between producer and consumer. Usage example, for Kingfisher extension board for Renesas Gen-3 Soc, that has WiFi interrupt delivered over inverting level-shifter: / { gpio1_25_inverted: inverter { compatible =3D "linux,irq-type-changer"; interrupt-controller; #interrupt-cells =3D <2>; interrupt-parent =3D <&gpio1>; interrupts =3D <25 IRQ_TYPE_EDGE_FALLING>; }; }; &wlcore { interrupt-parent =3D <&gpio1_25_inverted>; interrupts =3D <0 IRQ_TYPE_EDGE_RISING>; }; Then, wlcore driver observes IRQ_TYPE_EDGE_RISING trigger type and configures interrupt output as such. At the same time, gpio-rcar driver gets interrupt configured for IRQ_TYPE_EDGE_FALLING. This version uses hierarchical irq_domain API, and works only with parent interrupt domains compatible with that API. Signed-off-by: Nikita Yushchenko --- v1: https://lore.kernel.org/lkml/20220119201741.717770-1-nikita.yoush@cogen= tembedded.com/ Changes from v1: - fixed order of kzalloc() args, caught by kbuild robot drivers/irqchip/Kconfig | 18 ++++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-type-changer.c | 162 +++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 drivers/irqchip/irq-type-changer.c diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 7038957f4a77..7f348016e82c 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -617,4 +617,22 @@ config MCHP_EIC help Support for Microchip External Interrupt Controller. =20 +config IRQ_TYPE_CHANGER + bool "Interrupt trigger type changer" + select IRQ_DOMAIN + select IRQ_DOMAIN_HIERARCHY + help + Interrupt trigger type changer is designed to support boards that + modify (e.g. invert) signal between interrupt source and interrupt + controller input. So trigger type configured by a driver for some + interrupt output pin does not match trigger type that shall be used + to configure interrupt controller's input where that pin is connected. + + In this case, board device tree shall add an interrupt trigger + type changer node and use it as the interrupt parent for the node + representing interrupt source. Then, interrupt trigger type defined + in the interrupt source node will be visible for the interrupt source + driver, and (different) trigger type defined inside the changer node + will be used to configure the interrupt controller. + endmenu diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c1f611cbfbf8..57a664837857 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -117,3 +117,4 @@ obj-$(CONFIG_WPCM450_AIC) +=3D irq-wpcm450-aic.o obj-$(CONFIG_IRQ_IDT3243X) +=3D irq-idt3243x.o obj-$(CONFIG_APPLE_AIC) +=3D irq-apple-aic.o obj-$(CONFIG_MCHP_EIC) +=3D irq-mchp-eic.o +obj-$(CONFIG_IRQ_TYPE_CHANGER) +=3D irq-type-changer.o diff --git a/drivers/irqchip/irq-type-changer.c b/drivers/irqchip/irq-type-= changer.c new file mode 100644 index 000000000000..0f461fda6610 --- /dev/null +++ b/drivers/irqchip/irq-type-changer.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +struct changer { + unsigned long count; + struct { + struct irq_fwspec fwspec; + unsigned int type; + } out[0]; +}; + +static int changer_set_type(struct irq_data *data, unsigned int type) +{ + struct changer *ch =3D data->domain->host_data; + struct irq_data *parent_data =3D data->parent_data; + + return parent_data->chip->irq_set_type(parent_data, + ch->out[data->hwirq].type); +} + +static struct irq_chip changer_chip =3D { + .name =3D "type-changer", + .irq_mask =3D irq_chip_mask_parent, + .irq_unmask =3D irq_chip_unmask_parent, + .irq_eoi =3D irq_chip_eoi_parent, + .irq_set_type =3D changer_set_type, + .irq_retrigger =3D irq_chip_retrigger_hierarchy, + .irq_set_affinity =3D irq_chip_set_affinity_parent, + .irq_set_wake =3D irq_chip_set_wake_parent, +}; + +static int changer_domain_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + struct changer *ch =3D domain->host_data; + + if (fwspec->param_count !=3D 2) + return -EINVAL; + if (fwspec->param[0] >=3D ch->count) + return -ENXIO; + + *hwirq =3D fwspec->param[0]; + *type =3D fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + return 0; +} + +static int changer_domain_alloc(struct irq_domain *domain, unsigned int vi= rq, + unsigned int nr_irqs, void *arg) +{ + struct changer *ch =3D domain->host_data; + struct irq_fwspec *fwspec =3D arg; + irq_hw_number_t hwirq; + unsigned int type; + int ret; + + if (WARN_ON(nr_irqs !=3D 1)) + return -EINVAL; + + ret =3D changer_domain_translate(domain, fwspec, &hwirq, &type); + if (ret) + return ret; + + irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &changer_chip, ch); + + return irq_domain_alloc_irqs_parent(domain, virq, 1, + &ch->out[hwirq].fwspec); +} + +static const struct irq_domain_ops changer_domain_ops =3D { + .translate =3D changer_domain_translate, + .alloc =3D changer_domain_alloc, + .free =3D irq_domain_free_irqs_common, +}; + +static int __init changer_of_init(struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *domain, *parent_domain; + int count, i, ret; + struct changer *ch; + struct of_phandle_args pargs; + irq_hw_number_t unused; + + if (!parent) { + pr_err("%pOF: no parent node\n", node); + return -EINVAL; + } + + parent_domain =3D irq_find_host(parent); + if (!parent_domain) { + pr_err("%pOF: no parent domain\n", node); + return -EINVAL; + } + + if (WARN_ON(!parent_domain->ops->translate)) + return -EINVAL; + + count =3D of_irq_count(node); + if (count < 1) { + pr_err("%pOF: no interrupts defined\n", node); + return -EINVAL; + } + + ch =3D kzalloc(sizeof(*ch) + count * sizeof(ch->out[0]), GFP_KERNEL); + if (!ch) + return -ENOMEM; + ch->count =3D count; + + for (i =3D 0; i < count; i++) { + ret =3D of_irq_parse_one(node, i, &pargs); + if (ret) { + pr_err("%pOF: interrupt %d: error %d parsing\n", + node, i, ret); + goto out_free; + } + of_phandle_args_to_fwspec(pargs.np, pargs.args, + pargs.args_count, + &ch->out[i].fwspec); + ret =3D parent_domain->ops->translate(parent_domain, + &ch->out[i].fwspec, + &unused, + &ch->out[i].type); + if (ret) { + pr_err("%pOF: interrupt %d: error %d extracting type\n", + node, i, ret); + goto out_free; + } + if (ch->out[i].type =3D=3D IRQ_TYPE_NONE) { + pr_err("%pOF: interrupt %d: no type\n", node, i); + ret =3D -ENXIO; + goto out_free; + } + } + + domain =3D irq_domain_create_hierarchy(parent_domain, 0, count, + of_node_to_fwnode(node), + &changer_domain_ops, ch); + if (!domain) { + ret =3D -ENOMEM; + goto out_free; + } + + return 0; + +out_free: + kfree(ch); + return ret; +} + +IRQCHIP_PLATFORM_DRIVER_BEGIN(changer) +IRQCHIP_MATCH("linux,irq-type-changer", changer_of_init) +IRQCHIP_PLATFORM_DRIVER_END(changer) +MODULE_AUTHOR("Nikita Yushchenko "); +MODULE_DESCRIPTION("Virtual irqchip to support trigger type change in rout= e"); +MODULE_LICENSE("GPL v2"); --=20 2.30.2