From: Thierry Reding <tred...@nvidia.com>

Convert the Tegra186 GPIO driver to use the banked GPIO infrastructure,
which simplifies some parts of the driver.

Signed-off-by: Thierry Reding <tred...@nvidia.com>
---
 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 <linux/irq.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 
 #include <dt-bindings/gpio/tegra186-gpio.h>
@@ -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),
-- 
2.14.1

Reply via email to