Skip to content

Commit

Permalink
gpio: tegra186: Force one interrupt per bank
Browse files Browse the repository at this point in the history
Newer chips support up to 8 interrupts per bank, which can be useful to
balance the load and decrease latency. However, it also required a very
complicated interrupt routing to be set up. To keep things simple for
now, ensure that a single interrupt per bank is enforced, even if all
possible interrupts are described in device tree.

Signed-off-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
  • Loading branch information
Thierry Reding authored and Bartosz Golaszewski committed Sep 22, 2021
1 parent dcfd2a2 commit ca03874
Showing 1 changed file with 62 additions and 6 deletions.
68 changes: 62 additions & 6 deletions drivers/gpio/gpio-tegra186.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ struct tegra_gpio {
unsigned int *irq;

const struct tegra_gpio_soc *soc;
unsigned int num_irqs_per_bank;
unsigned int num_banks;

void __iomem *secure;
void __iomem *base;
Expand Down Expand Up @@ -594,6 +596,28 @@ static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
}
}

static unsigned int tegra186_gpio_irqs_per_bank(struct tegra_gpio *gpio)
{
struct device *dev = gpio->gpio.parent;

if (gpio->num_irq > gpio->num_banks) {
if (gpio->num_irq % gpio->num_banks != 0)
goto error;
}

if (gpio->num_irq < gpio->num_banks)
goto error;

gpio->num_irqs_per_bank = gpio->num_irq / gpio->num_banks;

return 0;

error:
dev_err(dev, "invalid number of interrupts (%u) for %u banks\n",
gpio->num_irq, gpio->num_banks);
return -EINVAL;
}

static int tegra186_gpio_probe(struct platform_device *pdev)
{
unsigned int i, j, offset;
Expand All @@ -608,7 +632,17 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
return -ENOMEM;

gpio->soc = device_get_match_data(&pdev->dev);
gpio->gpio.label = gpio->soc->name;
gpio->gpio.parent = &pdev->dev;

/* count the number of banks in the controller */
for (i = 0; i < gpio->soc->num_ports; i++)
if (gpio->soc->ports[i].bank > gpio->num_banks)
gpio->num_banks = gpio->soc->ports[i].bank;

gpio->num_banks++;

/* get register apertures */
gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
if (IS_ERR(gpio->secure)) {
gpio->secure = devm_platform_ioremap_resource(pdev, 0);
Expand All @@ -629,6 +663,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev)

gpio->num_irq = err;

err = tegra186_gpio_irqs_per_bank(gpio);
if (err < 0)
return err;

gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq),
GFP_KERNEL);
if (!gpio->irq)
Expand All @@ -642,9 +680,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->irq[i] = err;
}

gpio->gpio.label = gpio->soc->name;
gpio->gpio.parent = &pdev->dev;

gpio->gpio.request = gpiochip_generic_request;
gpio->gpio.free = gpiochip_generic_free;
gpio->gpio.get_direction = tegra186_gpio_get_direction;
Expand Down Expand Up @@ -708,7 +743,30 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
irq->parent_handler = tegra186_gpio_irq;
irq->parent_handler_data = gpio;
irq->num_parents = gpio->num_irq;
irq->parents = gpio->irq;

/*
* To simplify things, use a single interrupt per bank for now. Some
* chips support up to 8 interrupts per bank, which can be useful to
* distribute the load and decrease the processing latency for GPIOs
* but it also requires a more complicated interrupt routing than we
* currently program.
*/
if (gpio->num_irqs_per_bank > 1) {
irq->parents = devm_kcalloc(&pdev->dev, gpio->num_banks,
sizeof(*irq->parents), GFP_KERNEL);
if (!irq->parents)
return -ENOMEM;

for (i = 0; i < gpio->num_banks; i++)
irq->parents[i] = gpio->irq[i * gpio->num_irqs_per_bank];

irq->num_parents = gpio->num_banks;
} else {
irq->num_parents = gpio->num_irq;
irq->parents = gpio->irq;
}

tegra186_gpio_init_route_mapping(gpio);

np = of_find_matching_node(NULL, tegra186_pmc_of_match);
if (np) {
Expand All @@ -719,8 +777,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}

tegra186_gpio_init_route_mapping(gpio);

irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
sizeof(*irq->map), GFP_KERNEL);
if (!irq->map)
Expand Down

0 comments on commit ca03874

Please sign in to comment.