From patchwork Fri Sep 1 18:57:36 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thierry Reding X-Patchwork-Id: 808951 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; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="TB9yO/C1"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3xkT685B2Jz9sQl for ; Sat, 2 Sep 2017 04:58:24 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752601AbdIAS6M (ORCPT ); Fri, 1 Sep 2017 14:58:12 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:34363 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752588AbdIAS6J (ORCPT ); Fri, 1 Sep 2017 14:58:09 -0400 Received: by mail-wm0-f68.google.com with SMTP id l19so970036wmi.1; Fri, 01 Sep 2017 11:58:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=6HdMk8gqbdAzOBlpD1yg++ZCy9OJVxKiPShQ/RGw4ls=; b=TB9yO/C1kEPfKp9SBMqr6iiKd60Z1dcTVS1Cnt8aI5fvHjrcoHIrHuXwbKDUGLdPlu EjElXb3Ymc0eCY7wpub8TYWaM0KwGo1Eublr1T/7zvJ6RpLEYz8P7Bq9F0R4MMZWmMN/ pzvY3flXWEeg0nh5a+PthLL8u9r+q3FTTiMl5SfvGHE6SyQUBy8uLq0jcWJN98dxnQqo a6Pd9d1ifY2NlQa3SoAVIK+xLH0YsYHDUaIfWSeJwr6EI63t+C21Lzr7QM20gwSMBerX BJpaKx9IC+tcXvaw6VXJasv2QxQuJdZmvjO/ZCzBz4pzXWJ3Kf6encjqvDIIaqrZeVvz 0ujw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=6HdMk8gqbdAzOBlpD1yg++ZCy9OJVxKiPShQ/RGw4ls=; b=isaIg4Kq1BoXmZI/dhUVgrOuRbsjeIoT4SCJMXYRCu6LvUVJUH7y7Y2SOTV961fyUE A3AxkqDn5SchiKYlnKPdG79ZwfOk9aDyZ37rm/rTzXBlbRp+I9oqlFGh3J//zkVrqEda nBlAZTqJxZRZVKTc43wjuExArxtXvHK+cbEaUznP2S5ED2Uust5jRdMOTqHsYer95TY6 ihOmPb5kXp4a4qZJxUlD9L3v+XitHdE2L+gzBu+yMbnVAFiRlDV/YCsc25Vm9STvuwzr VSCC2+vHaiGhpOX7DS6PL3zFlQMu5J7fEkPHtBRdvAIryYsv876VHykNWs5GmOBdKah0 4NxQ== X-Gm-Message-State: AHPjjUhvStWglBzlDeMvePP9R2yqthIiHH94ANYScOyfJx0jv9eRIuhw h1X/Xpjm0f/dUKPk X-Google-Smtp-Source: ADKCNb7YWqrNTfCehhZkazmGAtpxI6NBAUbr/pTfrRadzzUzYqzynnHRn3V2rnN9uuoUmY6xXoq5sw== X-Received: by 10.28.1.86 with SMTP id 83mr1176667wmb.191.1504292287295; Fri, 01 Sep 2017 11:58:07 -0700 (PDT) Received: from localhost (p200300E41BD6D60076D02BFFFE273F51.dip0.t-ipconnect.de. [2003:e4:1bd6:d600:76d0:2bff:fe27:3f51]) by smtp.gmail.com with ESMTPSA id o191sm334549wmd.35.2017.09.01.11.58.06 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 01 Sep 2017 11:58:06 -0700 (PDT) From: Thierry Reding To: Linus Walleij Cc: Jonathan Hunter , linux-gpio@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 16/16] gpio: tegra186: Use banked GPIO infrastructure Date: Fri, 1 Sep 2017 20:57:36 +0200 Message-Id: <20170901185736.28051-17-thierry.reding@gmail.com> X-Mailer: git-send-email 2.13.3 In-Reply-To: <20170901185736.28051-1-thierry.reding@gmail.com> References: <20170901185736.28051-1-thierry.reding@gmail.com> Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org From: Thierry Reding Convert the Tegra186 GPIO driver to use the banked GPIO infrastructure, which simplifies some parts of the driver. Signed-off-by: Thierry Reding --- drivers/gpio/gpio-tegra186.c | 211 ++++++++++++++++--------------------------- 1 file changed, 79 insertions(+), 132 deletions(-) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 162dc6b41ae8..4926b98a05f6 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -44,15 +45,27 @@ #define TEGRA186_GPIO_INTERRUPT_STATUS(x) (0x100 + (x) * 4) -struct tegra_gpio_port { +struct tegra_gpio_port_soc { const char *name; unsigned int offset; unsigned int pins; unsigned int irq; }; +struct tegra_gpio_port { + struct gpio_bank bank; + unsigned int offset; + const char *name; +}; + +static inline struct tegra_gpio_port * +to_tegra_gpio_port(struct gpio_bank *bank) +{ + return container_of(bank, struct tegra_gpio_port, bank); +} + struct tegra_gpio_soc { - const struct tegra_gpio_port *ports; + const struct tegra_gpio_port_soc *ports; unsigned int num_ports; const char *name; }; @@ -60,21 +73,21 @@ struct tegra_gpio_soc { struct tegra_gpio { struct gpio_chip gpio; struct irq_chip intc; - unsigned int num_irq; - unsigned int *irq; const struct tegra_gpio_soc *soc; + struct tegra_gpio_port *ports; + void __iomem *base; }; -static const struct tegra_gpio_port * +static const struct tegra_gpio_port_soc * tegra186_gpio_get_port(struct tegra_gpio *gpio, unsigned int *pin) { unsigned int start = 0, i; for (i = 0; i < gpio->soc->num_ports; i++) { - const struct tegra_gpio_port *port = &gpio->soc->ports[i]; + const struct tegra_gpio_port_soc *port = &gpio->soc->ports[i]; if (*pin >= start && *pin < start + port->pins) { *pin -= start; @@ -90,7 +103,7 @@ tegra186_gpio_get_port(struct tegra_gpio *gpio, unsigned int *pin) static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio, unsigned int pin) { - const struct tegra_gpio_port *port; + const struct tegra_gpio_port_soc *port; port = tegra186_gpio_get_port(gpio, &pin); if (!port) @@ -206,39 +219,10 @@ static void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset, writel(value, base + TEGRA186_GPIO_OUTPUT_VALUE); } -static int tegra186_gpio_of_xlate(struct gpio_chip *chip, - const struct of_phandle_args *spec, - u32 *flags) -{ - struct tegra_gpio *gpio = gpiochip_get_data(chip); - unsigned int port, pin, i, offset = 0; - - if (WARN_ON(chip->of_gpio_n_cells < 2)) - return -EINVAL; - - if (WARN_ON(spec->args_count < chip->of_gpio_n_cells)) - return -EINVAL; - - port = spec->args[0] / 8; - pin = spec->args[0] % 8; - - if (port >= gpio->soc->num_ports) { - dev_err(chip->parent, "invalid port number: %u\n", port); - return -EINVAL; - } - - for (i = 0; i < port; i++) - offset += gpio->soc->ports[i].pins; - - if (flags) - *flags = spec->args[1]; - - return offset + pin; -} - static void tegra186_irq_ack(struct irq_data *data) { - struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data); + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct tegra_gpio *gpio = gpiochip_get_data(chip); void __iomem *base; base = tegra186_gpio_get_base(gpio, data->hwirq); @@ -250,7 +234,8 @@ static void tegra186_irq_ack(struct irq_data *data) static void tegra186_irq_mask(struct irq_data *data) { - struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data); + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct tegra_gpio *gpio = gpiochip_get_data(chip); void __iomem *base; u32 value; @@ -265,7 +250,8 @@ static void tegra186_irq_mask(struct irq_data *data) static void tegra186_irq_unmask(struct irq_data *data) { - struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data); + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct tegra_gpio *gpio = gpiochip_get_data(chip); void __iomem *base; u32 value; @@ -280,7 +266,8 @@ static void tegra186_irq_unmask(struct irq_data *data) static int tegra186_irq_set_type(struct irq_data *data, unsigned int flow) { - struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data); + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct tegra_gpio *gpio = gpiochip_get_data(chip); void __iomem *base; u32 value; @@ -332,76 +319,22 @@ static int tegra186_irq_set_type(struct irq_data *data, unsigned int flow) return 0; } -static void tegra186_gpio_irq(struct irq_desc *desc) -{ - struct tegra_gpio *gpio = irq_desc_get_handler_data(desc); - struct irq_domain *domain = gpio->gpio.irq.domain; - struct irq_chip *chip = irq_desc_get_chip(desc); - unsigned int parent = irq_desc_get_irq(desc); - unsigned int i, offset = 0; - - chained_irq_enter(chip, desc); - - for (i = 0; i < gpio->soc->num_ports; i++) { - const struct tegra_gpio_port *port = &gpio->soc->ports[i]; - void __iomem *base = gpio->base + port->offset; - unsigned int pin, irq; - unsigned long value; - - /* skip ports that are not associated with this controller */ - if (parent != gpio->irq[port->irq]) - goto skip; - - value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1)); - - for_each_set_bit(pin, &value, port->pins) { - irq = irq_find_mapping(domain, offset + pin); - if (WARN_ON(irq == 0)) - continue; - - generic_handle_irq(irq); - } - -skip: - offset += port->pins; - } - - chained_irq_exit(chip, desc); -} - -static int tegra186_gpio_irq_domain_xlate(struct irq_domain *domain, - struct device_node *np, - const u32 *spec, unsigned int size, - unsigned long *hwirq, - unsigned int *type) +static void tegra186_gpio_update_bank(struct gpio_bank *bank) { - struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data); - unsigned int port, pin, i, offset = 0; - - if (size < 2) - return -EINVAL; - - port = spec[0] / 8; - pin = spec[0] % 8; - - if (port >= gpio->soc->num_ports) { - dev_err(gpio->gpio.parent, "invalid port number: %u\n", port); - return -EINVAL; - } - - for (i = 0; i < port; i++) - offset += gpio->soc->ports[i].pins; + struct tegra_gpio_port *port = to_tegra_gpio_port(bank); + struct tegra_gpio *gpio = gpiochip_get_data(bank->chip); + void __iomem *base = gpio->base + port->offset; + u32 value; - *type = spec[1] & IRQ_TYPE_SENSE_MASK; - *hwirq = offset + pin; + value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1)); - return 0; + bank->pending[0] = value; } static const struct irq_domain_ops tegra186_gpio_irq_domain_ops = { .map = gpiochip_irq_map, .unmap = gpiochip_irq_unmap, - .xlate = tegra186_gpio_irq_domain_xlate, + .xlate = gpio_banked_irq_domain_xlate, }; static struct lock_class_key tegra186_gpio_lock_class; @@ -420,6 +353,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) return -ENOMEM; gpio->soc = of_device_get_match_data(&pdev->dev); + irq = &gpio->gpio.irq; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio"); gpio->base = devm_ioremap_resource(&pdev->dev, res); @@ -430,21 +364,47 @@ static int tegra186_gpio_probe(struct platform_device *pdev) if (err < 0) return err; - gpio->num_irq = err; + irq->num_parents = err; - gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq), - GFP_KERNEL); - if (!gpio->irq) + irq->parents = devm_kcalloc(&pdev->dev, irq->num_parents, + sizeof(*irq->parents), GFP_KERNEL); + if (!irq->parents) return -ENOMEM; - for (i = 0; i < gpio->num_irq; i++) { + for (i = 0; i < irq->num_parents; i++) { err = platform_get_irq(pdev, i); if (err < 0) return err; - gpio->irq[i] = err; + irq->parents[i] = err; } + gpio->ports = devm_kcalloc(&pdev->dev, gpio->soc->num_ports, + sizeof(struct tegra_gpio_port), + GFP_KERNEL); + if (!gpio->ports) + return -ENOMEM; + + gpio->gpio.banks = devm_kcalloc(&pdev->dev, gpio->soc->num_ports, + sizeof(struct gpio_bank *), + GFP_KERNEL); + if (!gpio->gpio.banks) + return -ENOMEM; + + for (i = 0; i < gpio->soc->num_ports; i++) { + const struct tegra_gpio_port_soc *soc = &gpio->soc->ports[i]; + struct tegra_gpio_port *port = &gpio->ports[i]; + + gpio->gpio.banks[i] = &port->bank; + port->bank.parent_irq = soc->irq; + port->bank.num_pins = soc->pins; + + port->offset = soc->offset; + port->name = soc->name; + } + + gpio->gpio.num_banks = gpio->soc->num_ports; + gpio->gpio.label = gpio->soc->name; gpio->gpio.parent = &pdev->dev; @@ -465,7 +425,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) return -ENOMEM; for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) { - const struct tegra_gpio_port *port = &gpio->soc->ports[i]; + const struct tegra_gpio_port_soc *port = &gpio->soc->ports[i]; char *name; for (j = 0; j < port->pins; j++) { @@ -484,7 +444,11 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->gpio.of_node = pdev->dev.of_node; gpio->gpio.of_gpio_n_cells = 2; - gpio->gpio.of_xlate = tegra186_gpio_of_xlate; + gpio->gpio.of_gpio_bank_shift = 3; + gpio->gpio.of_gpio_bank_mask = 0x1fffffff; + gpio->gpio.of_gpio_pin_shift = 0; + gpio->gpio.of_gpio_pin_mask = 0x7; + gpio->gpio.of_xlate = of_gpio_banked_xlate; gpio->intc.name = pdev->dev.of_node->name; gpio->intc.irq_ack = tegra186_irq_ack; @@ -492,31 +456,14 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->intc.irq_unmask = tegra186_irq_unmask; gpio->intc.irq_set_type = tegra186_irq_set_type; - irq = &gpio->gpio.irq; irq->chip = &gpio->intc; irq->first = 0; irq->domain_ops = &tegra186_gpio_irq_domain_ops; irq->handler = handle_simple_irq; irq->lock_key = &tegra186_gpio_lock_class; irq->default_type = IRQ_TYPE_NONE; - irq->parent_handler = tegra186_gpio_irq; - irq->parent_handler_data = gpio; - irq->num_parents = gpio->num_irq; - irq->parents = gpio->irq; - - irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio, - sizeof(*irq->map), GFP_KERNEL); - if (!irq->map) - return -ENOMEM; - - for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) { - const struct tegra_gpio_port *port = &gpio->soc->ports[i]; - - for (j = 0; j < port->pins; j++) - irq->map[offset + j] = irq->parents[port->irq]; - - offset += port->pins; - } + irq->parent_handler = gpio_irq_chip_banked_handler; + irq->update_bank = tegra186_gpio_update_bank; platform_set_drvdata(pdev, gpio); @@ -540,7 +487,7 @@ static int tegra186_gpio_remove(struct platform_device *pdev) .irq = controller, \ } -static const struct tegra_gpio_port tegra186_main_ports[] = { +static const struct tegra_gpio_port_soc tegra186_main_ports[] = { TEGRA_MAIN_GPIO_PORT( A, 0x2000, 7, 2), TEGRA_MAIN_GPIO_PORT( B, 0x3000, 7, 3), TEGRA_MAIN_GPIO_PORT( C, 0x3200, 7, 3), @@ -580,7 +527,7 @@ static const struct tegra_gpio_soc tegra186_main_soc = { .irq = controller, \ } -static const struct tegra_gpio_port tegra186_aon_ports[] = { +static const struct tegra_gpio_port_soc tegra186_aon_ports[] = { TEGRA_AON_GPIO_PORT( S, 0x0200, 5, 0), TEGRA_AON_GPIO_PORT( U, 0x0400, 6, 0), TEGRA_AON_GPIO_PORT( V, 0x0800, 8, 0),