From patchwork Thu Sep 28 09:56:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thierry Reding X-Patchwork-Id: 819493 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-tegra-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="PzU27G5E"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3y2qqb2ZHZz9tXN for ; Thu, 28 Sep 2017 19:57:31 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753002AbdI1J5R (ORCPT ); Thu, 28 Sep 2017 05:57:17 -0400 Received: from mail-qk0-f193.google.com ([209.85.220.193]:38873 "EHLO mail-qk0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752952AbdI1J5O (ORCPT ); Thu, 28 Sep 2017 05:57:14 -0400 Received: by mail-qk0-f193.google.com with SMTP id q8so640312qkl.5; Thu, 28 Sep 2017 02:57:13 -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=R4d9KlgaXN4Eklb2v4ejQbNuz5P1Zazx4aiC+7rzg5s=; b=PzU27G5EzZAdMp2xKwqVbMwU7qCOvdsxvgnexaPtZt7A+A7mgpjXve7LsTriqq8aTQ jeSxn5MIy0YvslQ5AUpQIUarCgMsEetUogU+91TrmiOpFfABer0oeQ6xyNcvgLINMj5Z 3RB0rgarU2hiI+M2pwud3OxhfAJEKqqbI4dnqR6W3C4wNif5W23dvDH7KFPo0UpieePU ZsQ/2oRsmZKFCVOLH83hh9x5HeikW5KkISePPyEqGQhXPe7dDkZaC+oWbbu1x/9NWO7N yZ7KicOL2pkRByQHnVPZ5RieUG1dm77PjxRH451zCRrbW1NAkrgTMj4IGxGCAsjt00Gy BByQ== 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=R4d9KlgaXN4Eklb2v4ejQbNuz5P1Zazx4aiC+7rzg5s=; b=oTVpgVt6dy2VKxDMXvtlTypb/n60PgisMAxAGReg67e/yXYn0Ke1qdcu7MFiPX/28b 4olOh8j9TSb3fwqRr4ZsX4KIkn7rILzUa/OyB4LAft6iI/m9tZTMIUBimK+8LfDHMbCl 3nUH7/94jHe0aAUOOCGJ9MK1j0uk2CNaKiyB9poEsbeFah+gaA5qStsyDqGzklqmzDKa Fe0BOjUgGQ2957zNdjSyua232e54O1WG+P0QErnoa7G5aGzdSMiOQ6uGrzvEu1Cl0fYD 7N9FxaLnVJAHpJLQQLQfabEDkwCQUDZngOCaBancV3P+3gdyaVu1UmBFjyD7wKKEAQJE HNzg== X-Gm-Message-State: AHPjjUitwJBabcMphFTkYxODJ6ZskdlSds2u01szvwDHtXXijJSJ4Vaa Y4GzhN3cga4P4zFV4DJo8DA= X-Google-Smtp-Source: AOwi7QCnicQp+2tvpHHUXERNIStLBM1wX6RUiyNBfKudJdApUePoZTP2eV4VtiDXsRUilZD+VsyRnA== X-Received: by 10.55.182.71 with SMTP id g68mr6284775qkf.227.1506592633276; Thu, 28 Sep 2017 02:57:13 -0700 (PDT) Received: from localhost (p200300E41BCC8100EA54DC343767CF80.dip0.t-ipconnect.de. [2003:e4:1bcc:8100:ea54:dc34:3767:cf80]) by smtp.gmail.com with ESMTPSA id u17sm782091qtc.15.2017.09.28.02.57.12 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 28 Sep 2017 02:57:12 -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 v2 16/16] gpio: tegra186: Use banked GPIO infrastructure Date: Thu, 28 Sep 2017 11:56:28 +0200 Message-Id: <20170928095628.21966-17-thierry.reding@gmail.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170928095628.21966-1-thierry.reding@gmail.com> References: <20170928095628.21966-1-thierry.reding@gmail.com> Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@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..7da8e5248d15 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_lines = 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_line_shift = 0; + gpio->gpio.of_gpio_line_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_chained_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),