Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp737355imm; Wed, 25 Jul 2018 05:28:37 -0700 (PDT) X-Google-Smtp-Source: AAOMgpcWMdbZ18t0WUaX0EMvXHfrxYPaxwCT8R2kIyiBup52+THALEgb8MJdjDj8XV9LcHNGXdXh X-Received: by 2002:a62:9f85:: with SMTP id v5-v6mr21986828pfk.27.1532521717523; Wed, 25 Jul 2018 05:28:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1532521717; cv=none; d=google.com; s=arc-20160816; b=IZ5VOiijzdO0PApFP9XBGH8iw4MRUrTE1CTu0Te6t/Mz6KExf3QT4wSXaVv3KzNSc8 Xo6d5WQtqodmC6n80/4EgygxgublXXTLvGtPX+MgeMJeHozyKlaR3/2gTZAbvzepTpuZ +bWa9dCpJRE9+1irOJkgmWenKodYzU5bMUu3CYo7XFqZBrCuyd0S0YyiLY5czWXyTsiP yuzxMKgOYK+iODwceoky2v+JqQS5/D700OSnikgc1bD14ZvyrnMtlG4KtG6WDhXE5aM3 TfX0mswSFBvKTKx4xsxmF7B4taGRSuhX4I/ef6zRB7xGsE+hd2MSVKkfJkUA327cR/+P vrIg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=S0GM3kRnDeTnVe8Orb97iKWyGf47q1223jmsLkfz0ug=; b=SXs2EcNcN6JjYQ2HdTN+OpQA0MAzSj8iEE+M5ycWcMni5Tv83V8qv1AWv5kZRbYmgC QJSRMS6TRdQP4yaiWpkCDqNGpQKHU6NyWue+6HD/Cwf/uww4/3PC67+9vDqF6XLw9Eee x0SW7NTM1mYOwfwM/HNF8LEkkWS7TEq1ODjaEWQr8tHgNW1OcMCWfNHFy4nolavtukEG VZuUT6Gk9XlRsWHAMGtz7tQa02rvHWinVLFndaxzTByGXbIOVCGv0SVvJjZQ+yd24bux Kcitdoi4xEFP8Kw2Db1vz85d4ZTGClC11lSzrBjMqHGRqadiK9MCXX8tySSgUZ++He5J F0xg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 6-v6si13517287pgv.508.2018.07.25.05.28.22; Wed, 25 Jul 2018 05:28:37 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729068AbeGYNim (ORCPT + 99 others); Wed, 25 Jul 2018 09:38:42 -0400 Received: from mail.bootlin.com ([62.4.15.54]:33585 "EHLO mail.bootlin.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728791AbeGYNim (ORCPT ); Wed, 25 Jul 2018 09:38:42 -0400 Received: by mail.bootlin.com (Postfix, from userid 110) id 070222091A; Wed, 25 Jul 2018 14:27:12 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail.bootlin.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT, URIBL_BLOCKED shortcircuit=ham autolearn=disabled version=3.4.0 Received: from localhost.localdomain (unknown [80.255.6.130]) by mail.bootlin.com (Postfix) with ESMTPSA id BE297207B3; Wed, 25 Jul 2018 14:26:51 +0200 (CEST) From: Quentin Schulz To: alexandre.belloni@bootlin.com, robh+dt@kernel.org, mark.rutland@arm.com, linus.walleij@linaro.org Cc: ralf@linux-mips.org, paul.burton@mips.com, jhogan@kernel.org, linux-gpio@vger.kernel.org, linux-mips@linux-mips.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Quentin Schulz Subject: [PATCH 2/2] pinctrl: ocelot: add support for interrupt controller Date: Wed, 25 Jul 2018 14:26:21 +0200 Message-Id: <20180725122621.31713-2-quentin.schulz@bootlin.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20180725122621.31713-1-quentin.schulz@bootlin.com> References: <20180725122621.31713-1-quentin.schulz@bootlin.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This GPIO controller can serve as an interrupt controller as well on the GPIOs it handles. An interrupt is generated whenever a GPIO line changes and the interrupt for this GPIO line is enabled. This means that both the changes from low to high and high to low generate an interrupt. For some use cases, it makes sense to ignore the high to low change and not generate an interrupt. Such a use case is a line that is hold in a level high/low manner until the event holding the line gets acked. This can be achieved by making sure the interrupt on the GPIO controller side gets acked and masked only after the line gets hold in its default state, this is what's done with the fasteoi functions. Only IRQ_TYPE_EDGE_BOTH and IRQ_TYPE_LEVEL_HIGH are supported for now. Signed-off-by: Quentin Schulz --- drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/pinctrl-ocelot.c | 102 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index dd50371225bc..891d80ef038a 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -332,6 +332,7 @@ config PINCTRL_OCELOT depends on OF depends on MSCC_OCELOT || COMPILE_TEST select GPIOLIB + select GPIOLIB_IRQCHIP select GENERIC_PINCONF select GENERIC_PINCTRL_GROUPS select GENERIC_PINMUX_FUNCTIONS diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c index 15bb1cb8729b..d80b32413b09 100644 --- a/drivers/pinctrl/pinctrl-ocelot.c +++ b/drivers/pinctrl/pinctrl-ocelot.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -427,11 +428,98 @@ static const struct gpio_chip ocelot_gpiolib_chip = { .owner = THIS_MODULE, }; +static void ocelot_irq_mask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct ocelot_pinctrl *info = gpiochip_get_data(chip); + unsigned int gpio = irqd_to_hwirq(data); + + regmap_update_bits(info->map, OCELOT_GPIO_INTR_ENA, BIT(gpio), 0); +} + +static void ocelot_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct ocelot_pinctrl *info = gpiochip_get_data(chip); + unsigned int gpio = irqd_to_hwirq(data); + + regmap_update_bits(info->map, OCELOT_GPIO_INTR_ENA, BIT(gpio), + BIT(gpio)); +} + +static void ocelot_irq_ack(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct ocelot_pinctrl *info = gpiochip_get_data(chip); + unsigned int gpio = irqd_to_hwirq(data); + + regmap_write_bits(info->map, OCELOT_GPIO_INTR, BIT(gpio), BIT(gpio)); +} + +static int ocelot_irq_set_type(struct irq_data *data, unsigned int type); + +static struct irq_chip ocelot_eoi_irqchip = { + .name = "gpio", + .irq_mask = ocelot_irq_mask, + .irq_eoi = ocelot_irq_ack, + .irq_unmask = ocelot_irq_unmask, + .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED, + .irq_set_type = ocelot_irq_set_type, +}; + +static struct irq_chip ocelot_irqchip = { + .name = "gpio", + .irq_mask = ocelot_irq_mask, + .irq_ack = ocelot_irq_ack, + .irq_unmask = ocelot_irq_unmask, + .irq_set_type = ocelot_irq_set_type, +}; + +static int ocelot_irq_set_type(struct irq_data *data, unsigned int type) +{ + type &= IRQ_TYPE_SENSE_MASK; + + if (!(type & (IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_HIGH))) + return -EINVAL; + + if (type & IRQ_TYPE_LEVEL_HIGH) + irq_set_chip_handler_name_locked(data, &ocelot_eoi_irqchip, + handle_fasteoi_irq, NULL); + if (type & IRQ_TYPE_EDGE_BOTH) + irq_set_chip_handler_name_locked(data, &ocelot_irqchip, + handle_edge_irq, NULL); + + return 0; +} + +static void ocelot_irq_handler(struct irq_desc *desc) +{ + struct irq_chip *parent_chip = irq_desc_get_chip(desc); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + struct ocelot_pinctrl *info = gpiochip_get_data(chip); + unsigned int reg = 0, irq; + unsigned long irqs; + + regmap_read(info->map, OCELOT_GPIO_INTR_IDENT, ®); + if (!reg) + return; + + chained_irq_enter(parent_chip, desc); + + irqs = reg; + + for_each_set_bit(irq, &irqs, OCELOT_PINS) { + generic_handle_irq(irq_linear_revmap(chip->irq.domain, irq)); + } + + chained_irq_exit(parent_chip, desc); +} + static int ocelot_gpiochip_register(struct platform_device *pdev, struct ocelot_pinctrl *info) { struct gpio_chip *gc; - int ret; + int ret, irq; info->gpio_chip = ocelot_gpiolib_chip; @@ -446,7 +534,17 @@ static int ocelot_gpiochip_register(struct platform_device *pdev, if (ret) return ret; - /* TODO: this can be used as an irqchip but no board is using that */ + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (irq <= 0) + return irq; + + ret = gpiochip_irqchip_add(gc, &ocelot_irqchip, 0, handle_edge_irq, + IRQ_TYPE_NONE); + if (ret) + return ret; + + gpiochip_set_chained_irqchip(gc, &ocelot_irqchip, irq, + ocelot_irq_handler); return 0; } -- 2.14.1