Commit ca038748 authored by Thierry Reding's avatar Thierry Reding Committed by Bartosz Golaszewski
Browse files

gpio: tegra186: Force one interrupt per bank



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: default avatarThierry Reding <treding@nvidia.com>
Reviewed-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarBartosz Golaszewski <brgl@bgdev.pl>
parent dcfd2a29
Loading
Loading
Loading
Loading
+62 −6
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
@@ -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)
@@ -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;
@@ -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;

	/*
	 * 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) {
@@ -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)