From patchwork Mon Jul 23 15:03:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans Verkuil X-Patchwork-Id: 947830 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-gpio-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=xs4all.nl Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 41Z4W85Pl7z9s0R for ; Tue, 24 Jul 2018 01:03:32 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388104AbeGWQFJ (ORCPT ); Mon, 23 Jul 2018 12:05:09 -0400 Received: from lb1-smtp-cloud9.xs4all.net ([194.109.24.22]:52603 "EHLO lb1-smtp-cloud9.xs4all.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387910AbeGWQFJ (ORCPT ); Mon, 23 Jul 2018 12:05:09 -0400 Received: from [IPv6:2001:983:e9a7:1:e00a:ef61:ab84:2596] ([IPv6:2001:983:e9a7:1:e00a:ef61:ab84:2596]) by smtp-cloud9.xs4all.net with ESMTPA id hcMxfr9jDEJtchcMyfIakv; Mon, 23 Jul 2018 17:03:29 +0200 Subject: [RFC PATCH] gpiolib: chain irq_request/release_resources() and irq_dis/enable() To: Linus Walleij Cc: Marc Zyngier , Thomas Gleixner , "open list:GPIO SUBSYSTEM" References: <8c586fd0-7deb-82bf-4c3b-3e2d0a3d1738@xs4all.nl> From: Hans Verkuil Message-ID: <8f580295-9742-0896-7a11-346f8f74e95e@xs4all.nl> Date: Mon, 23 Jul 2018 17:03:27 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.8.0 MIME-Version: 1.0 In-Reply-To: Content-Language: en-US X-CMAE-Envelope: MS4wfJeQNcq55vxuFaA5vk9bnEaFBAAPiMhMV7uYLkJCO0ssOC+MjJSGVr5TCoeYIlfMrb2V/eU7DqEf6ZnRUDtPw+hL9BfshpkoGk0scGcU38AR5ksOyKlL IVXmPTl4OZipezzi67IPPYF21/KlM0vOsVRaXVa6cOd4oSy0TWE0LaRyh8x3s9zRuSLDgqnvr1yIsyvzKbs2pfd5hhtzDV7dY6hcJMwWd1fltIGG3ORBXdhy f9UrT/UFPZMjH2rq+4UYluuSfstiWrLCoiF589rjNTKmcg1LwxlYaKh1OaR0ZBOJKz09LycbfaBtimo1v76GM5imb5htgIAHxIJ3IRWZfAxo07gDxlKHjP5c RZu+d3z24Q8u0Elz7tTqonEmHKLfhA== Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Hi all, Here is yet another attempt to allow drivers to disable the irq and drive the gpio as an output. Please be gentle with me: I am neither an expert on the gpio internals, nor on the irq internals. This patch lets gpiolib override the irq_chip's irq_request/release_resources and irq_en/disable hooks. The old hooks are stored and called by gpiolib. As a result, the gpiochip_(un)lock_as_irq functions can become static (not yet implemented in this patch) and these calls should be removed from all drivers. I haven't done that since I first want to know if what I am doing here even makes sense. Reviewing the removal of those calls in drivers should be fairly easy. Regards, Hans Signed-off-by: Hans Verkuil --- drivers/gpio/gpiolib.c | 78 +++++++++++++++++++++++-------------- include/linux/gpio/driver.h | 5 +++ 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e11a3bb03820..20429197756f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1800,28 +1800,48 @@ static const struct irq_domain_ops gpiochip_domain_ops = { static int gpiochip_irq_reqres(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + int res = 0; if (!try_module_get(chip->gpiodev->owner)) return -ENODEV; - - if (gpiochip_lock_as_irq(chip, d->hwirq)) { - chip_err(chip, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); + if (chip->irq.chip->irq_request_resources) + res = chip->irq.chip->irq_request_resources(d); + if (res) module_put(chip->gpiodev->owner); - return -EINVAL; - } - return 0; + return res; } static void gpiochip_irq_relres(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); - gpiochip_unlock_as_irq(chip, d->hwirq); + if (chip->irq.chip->irq_release_resources) + chip->irq.chip->irq_release_resources(d); module_put(chip->gpiodev->owner); } +static void gpiochip_irq_enable(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + WARN_ON(gpiochip_lock_as_irq(chip, d->hwirq)); + if (chip->irq.chip->irq_enable) + chip->irq.chip->irq_enable(d); + else + chip->irq.chip->irq_unmask(d); +} + +static void gpiochip_irq_disable(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + gpiochip_unlock_as_irq(chip, d->hwirq); + if (chip->irq.chip->irq_disable) + chip->irq.chip->irq_disable(d); + else + chip->irq.chip->irq_mask(d); +} + static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) { if (!gpiochip_irqchip_irq_valid(chip, offset)) @@ -1889,16 +1909,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, if (!gpiochip->irq.domain) return -EINVAL; - /* - * It is possible for a driver to override this, but only if the - * alternative functions are both implemented. - */ - if (!irqchip->irq_request_resources && - !irqchip->irq_release_resources) { - irqchip->irq_request_resources = gpiochip_irq_reqres; - irqchip->irq_release_resources = gpiochip_irq_relres; - } - if (gpiochip->irq.parent_handler) { void *data = gpiochip->irq.parent_handler_data ?: gpiochip; @@ -1956,8 +1966,16 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) } if (gpiochip->irq.chip) { - gpiochip->irq.chip->irq_request_resources = NULL; - gpiochip->irq.chip->irq_release_resources = NULL; + gpiochip->irq.chip->irq_request_resources = + gpiochip->irq.irq_request_resources; + gpiochip->irq.chip->irq_release_resources = + gpiochip->irq.irq_release_resources; + gpiochip->irq.chip->irq_enable = gpiochip->irq.irq_enable; + gpiochip->irq.chip->irq_disable = gpiochip->irq.irq_disable; + gpiochip->irq.irq_request_resources = NULL; + gpiochip->irq.irq_release_resources = NULL; + gpiochip->irq.irq_enable = NULL; + gpiochip->irq.irq_disable = NULL; gpiochip->irq.chip = NULL; } @@ -2048,15 +2066,15 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, return -EINVAL; } - /* - * It is possible for a driver to override this, but only if the - * alternative functions are both implemented. - */ - if (!irqchip->irq_request_resources && - !irqchip->irq_release_resources) { - irqchip->irq_request_resources = gpiochip_irq_reqres; - irqchip->irq_release_resources = gpiochip_irq_relres; - } + gpiochip->irq.irq_request_resources = irqchip->irq_request_resources; + gpiochip->irq.irq_release_resources = irqchip->irq_release_resources; + gpiochip->irq.irq_enable = irqchip->irq_enable; + gpiochip->irq.irq_disable = irqchip->irq_disable; + + irqchip->irq_request_resources = gpiochip_irq_reqres; + irqchip->irq_release_resources = gpiochip_irq_relres; + irqchip->irq_enable = gpiochip_irq_enable; + irqchip->irq_disable = gpiochip_irq_disable; acpi_gpiochip_request_interrupts(gpiochip); diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 5382b5183b7e..e352dd160424 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -138,6 +138,11 @@ struct gpio_irq_chip { * will allocate and map all IRQs during initialization. */ unsigned int first; + + int (*irq_request_resources)(struct irq_data *data); + void (*irq_release_resources)(struct irq_data *data); + void (*irq_enable)(struct irq_data *data); + void (*irq_disable)(struct irq_data *data); }; static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)