Received: by 2002:a05:7412:8d10:b0:f3:1519:9f41 with SMTP id bj16csp178671rdb; Tue, 5 Dec 2023 02:13:44 -0800 (PST) X-Google-Smtp-Source: AGHT+IEP0zLujLqO14HUkFTVNZ7ZAY1aMvItJkqULHbkGSV2xjdR9btcdm/dJnr0+mWAA9kcjrGX X-Received: by 2002:a05:6a21:3409:b0:18f:97c:978d with SMTP id yn9-20020a056a21340900b0018f097c978dmr6472298pzb.117.1701771223828; Tue, 05 Dec 2023 02:13:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1701771223; cv=none; d=google.com; s=arc-20160816; b=jc5fWxUHtFottQMcScJez9IBoPdqNKoc674bSfnsq8/NA53MttQFR7b79pnaSuRT1e ZcPoJsAkC/BCK9EWgqXJJuxMReJxdghUi0LMOEpd4zkDkoqTDA73Tmcq2B8WCHxBx7oP vB+v5R7IeFSAAH8PkAbYxXPPTQOsv/5I2td1y0MX9I85PBbbHszd2ygnfXVLqaF+Uf2B E3dmO/5OzECo0Otll63me0PmrDiecoqvHPzODNRjjCR+Hd+Z0DKasJkPA4D9S5KmxoXY H8yY6pATB2RoAfmKfBZTXssVF0dXrn/2om58jQ961YDsfEgKnwOnE4HSVpJSCYik9Upm W9RA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=9wMpucSn5zqjBO/aLjGsk6JeqaPw1zaj//dT7klLklQ=; fh=S4scCjmGHuTpFNsRpx5F7zvdPnZW78Fse4yFoJp+Y6U=; b=Dya0t1DjCgS8uCcfcq2fg0d0wWA9hzXWzzUKhcYG7pRrpiNds6SfGmRibZR88fJaTT 41Oo17ECJK+cBXcGMzLCKB9TFswk86eMzRQqDvbJ+O/oK3pJvNkfJ+bU5K5VGhamZtil DXLQq6VcLJo7NrdcKjrvHphB2bf8RtzL4D1K1Cm5yjjvVqnrdBa2ibGHkNKbcO2k+LIf AKD9onTpDZLh0GJ2wuABzGx98Cv9VUwIQ19SfWQb6/ADztXlTwz7pPca7YoMF8Fpd+8I YyKXhPBRSE/Z/X6VhG0stSPvWYzCNOQr4PY+FOuTfi/Vwtkiz3mEcRhzoJQkDxZUY8Aq 9RGQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.35 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from groat.vger.email (groat.vger.email. [23.128.96.35]) by mx.google.com with ESMTPS id y9-20020a056a00190900b006ce09c2c3d7si5449035pfi.267.2023.12.05.02.13.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 Dec 2023 02:13:43 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.35 as permitted sender) client-ip=23.128.96.35; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.35 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by groat.vger.email (Postfix) with ESMTP id 1FBBA807C57D; Tue, 5 Dec 2023 02:13:36 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.11 at groat.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1346528AbjLEKND (ORCPT + 99 others); Tue, 5 Dec 2023 05:13:03 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57968 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344954AbjLEJzb (ORCPT ); Tue, 5 Dec 2023 04:55:31 -0500 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 362BA181; Tue, 5 Dec 2023 01:55:36 -0800 (PST) Received: from SIOS1075.ysato.name (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id CD2461C058F; Tue, 5 Dec 2023 18:46:37 +0900 (JST) From: Yoshinori Sato To: linux-sh@vger.kernel.org Cc: Yoshinori Sato , Damien Le Moal , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Geert Uytterhoeven , Michael Turquette , Stephen Boyd , David Airlie , Daniel Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Thomas Gleixner , Lorenzo Pieralisi , =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= , Bjorn Helgaas , Greg Kroah-Hartman , Jiri Slaby , Magnus Damm , Daniel Lezcano , Rich Felker , John Paul Adrian Glaubitz , Lee Jones , Helge Deller , Heiko Stuebner , Jernej Skrabec , Chris Morgan , Linus Walleij , Randy Dunlap , Arnd Bergmann , Hyeonggon Yoo <42.hyeyoo@gmail.com>, David Rientjes , Vlastimil Babka , Baoquan He , Andrew Morton , Guenter Roeck , Stephen Rothwell , Guo Ren , Javier Martinez Canillas , Azeem Shaikh , Palmer Dabbelt , Bin Meng , Max Filippov , Tom Rix , Herve Codina , Jacky Huang , Lukas Bulwahn , Jonathan Corbet , Biju Das , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= , Sam Ravnborg , Michael Karcher , Sergey Shtylyov , Laurent Pinchart , linux-ide@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-clk@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org, linux-serial@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [DO NOT MERGE v5 18/37] irqchip: SH7751 IRL external encoder with enable gate. Date: Tue, 5 Dec 2023 18:45:37 +0900 Message-Id: <16941383a95369b239f7e913cf00ccd0c2e5c954.1701768028.git.ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-0.8 required=5.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on groat.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (groat.vger.email [0.0.0.0]); Tue, 05 Dec 2023 02:13:36 -0800 (PST) SH7751 have 15 level external interrupt. It is typically connected to the CPU through a priority encoder that can suppress requests. This driver provides a way to control those hardware with irqchip. Signed-off-by: Yoshinori Sato --- drivers/irqchip/Kconfig | 7 + drivers/irqchip/Makefile | 2 + drivers/irqchip/irq-renesas-sh7751irl.c | 227 ++++++++++++++++++++++++ 3 files changed, 236 insertions(+) create mode 100644 drivers/irqchip/irq-renesas-sh7751irl.c diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 658523f65b1d..2a061c01f381 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -687,4 +687,11 @@ config RENESAS_SH7751_INTC Support for the Renesas SH7751 On-chip interrupt controller. And external interrupt encoder for some targets. +config RENESAS_SH7751IRL_INTC + bool "Renesas SH7751 based target IRL encoder support." + depends on RENESAS_SH7751_INTC + help + Support for External Interrupt encoder + on the some Renesas SH7751 based target. + endmenu diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 26c91d075e25..91df16726b1f 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -121,3 +121,5 @@ obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o obj-$(CONFIG_SUNPLUS_SP7021_INTC) += irq-sp7021-intc.o obj-$(CONFIG_RENESAS_SH7751_INTC) += irq-renesas-sh7751.o +obj-$(CONFIG_RENESAS_SH7751IRL_INTC) += irq-renesas-sh7751irl.o + diff --git a/drivers/irqchip/irq-renesas-sh7751irl.c b/drivers/irqchip/irq-renesas-sh7751irl.c new file mode 100644 index 000000000000..99ee5bf9fb1e --- /dev/null +++ b/drivers/irqchip/irq-renesas-sh7751irl.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SH7751 based board IRL encoder driver + * (Renesas RTS7751R2D / IO DATA DEVICE LANDISK, USL-5P) + * + * Copyright (C) 2023 Yoshinori Sato + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct sh7751irl_intc_priv { + struct irq_domain *irq_domain; + void __iomem *base; + unsigned int width; + bool invert; + u32 enable_bit[NR_IRL]; +}; + +static inline unsigned long get_reg(void __iomem *addr, unsigned int w) +{ + switch (w) { + case 8: + return __raw_readb(addr); + case 16: + return __raw_readw(addr); + case 32: + return __raw_readl(addr); + default: + /* The size is checked when reading the properties. */ + pr_err("%s: Invalid width %d", __FILE__, w); + return 0; + } +} + +static inline void set_reg(void __iomem *addr, unsigned int w, unsigned long val) +{ + switch (w) { + case 8: + __raw_writeb(val, addr); + break; + case 16: + __raw_writew(val, addr); + break; + case 32: + __raw_writel(val, addr); + break; + default: + pr_err("%s: Invalid width %d", __FILE__, w); + } +} + +static inline struct sh7751irl_intc_priv *irq_data_to_priv(struct irq_data *data) +{ + return data->domain->host_data; +} + +static void irl_endisable(struct irq_data *data, unsigned int enable) +{ + struct sh7751irl_intc_priv *priv; + unsigned long val; + unsigned int irl; + + priv = irq_data_to_priv(data); + irl = irqd_to_hwirq(data) - IRL_BASE_IRQ; + + if (irl < NR_IRL && priv->enable_bit[irl] < priv->width) { + if (priv->invert) + enable = !enable; + + val = get_reg(priv->base, priv->width); + if (enable) + set_bit(priv->enable_bit[irl], &val); + else + clear_bit(priv->enable_bit[irl], &val); + set_reg(priv->base, priv->width, val); + } else { + pr_err("%s: Invalid register define in IRL %u", __FILE__, irl); + } +} + +static void sh7751irl_intc_disable_irq(struct irq_data *data) +{ + irl_endisable(data, 0); +} + +static void sh7751irl_intc_enable_irq(struct irq_data *data) +{ + irl_endisable(data, 1); +} + +static struct irq_chip sh7751irl_intc_chip = { + .name = "SH7751IRL-INTC", + .irq_enable = sh7751irl_intc_enable_irq, + .irq_disable = sh7751irl_intc_disable_irq, +}; + +static int sh7751irl_intc_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw_irq_num) +{ + irq_set_chip_and_handler(virq, &sh7751irl_intc_chip, handle_level_irq); + irq_get_irq_data(virq)->chip_data = h->host_data; + irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOPROBE); + return 0; +} + +static int sh7751irl_intc_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, unsigned long *hwirq, + unsigned int *type) +{ + if (fwspec->param[0] > NR_IRL) + return -EINVAL; + + switch (fwspec->param_count) { + case 2: + *type = fwspec->param[1]; + fallthrough; + case 1: + *hwirq = fwspec->param[0] + IRL_BASE_IRQ; + break; + default: + return -EINVAL; + } + return 0; +} + +static const struct irq_domain_ops sh7751irl_intc_domain_ops = { + .map = sh7751irl_intc_map, + .translate = sh7751irl_intc_translate, +}; + +static int __init load_irq_bit(struct device_node *node, struct sh7751irl_intc_priv *priv) +{ + struct property *enable_map; + const __be32 *p; + u32 nr_bits; + u32 irl; + int ret; + + /* Fill in unused */ + memset(priv->enable_bit, ~0, sizeof(priv->enable_bit)); + + enable_map = of_find_property(node, "renesas,enable-bit", &nr_bits); + if (IS_ERR(enable_map)) + return PTR_ERR(enable_map); + + nr_bits /= sizeof(u32); + /* 2words per entry. */ + if (nr_bits % 2) + return -EINVAL; + nr_bits /= 2; + if (nr_bits > NR_IRL) + return -EINVAL; + + ret = nr_bits; + p = NULL; + for (; nr_bits > 0; nr_bits--) { + /* 1st word - IRL */ + p = of_prop_next_u32(enable_map, p, &irl); + if (!p || irl > NR_IRL) + return -EINVAL; + /* 2nd word - enable bit index */ + p = of_prop_next_u32(enable_map, p, &priv->enable_bit[irl]); + if (priv->enable_bit[irl] >= priv->width) + return -EINVAL; + } + return ret; +} + +static int __init sh7751irl_init(struct device_node *node, struct device_node *parent) +{ + struct sh7751irl_intc_priv *priv; + struct irq_domain *d; + void __iomem *base; + int ret = 0; + + base = of_iomap(node, 0); + if (!base) + ret = -EINVAL; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base = base; + of_property_read_u32(node, "renesas,width", &priv->width); + if (priv->width != 8 && priv->width != 16 && priv->width != 32) { + pr_err("%pOFP: Invalid register width.\n", node); + ret = -EINVAL; + goto error; + } + + priv->invert = of_property_read_bool(node, "renesas,set-to-disable"); + + ret = load_irq_bit(node, priv); + if (ret < 0) { + pr_err("%pOFP: Invalid register define.\n", node); + goto error; + } + + d = irq_domain_add_tree(node, &sh7751irl_intc_domain_ops, priv); + if (d == NULL) { + pr_err("%pOFP: cannot initialize irq domain\n", node); + ret = -ENOMEM; + goto error; + } + + priv->irq_domain = d; + irq_domain_update_bus_token(d, DOMAIN_BUS_WIRED); + pr_info("%pOFP: SH7751 External Interrupt encoder (input=%d)", node, ret); + return 0; +error: + kfree(priv); + return ret; +} + +IRQCHIP_DECLARE(renesas_sh7751_irl, "renesas,sh7751-irl-ext", sh7751irl_init); -- 2.39.2