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

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
...@@ -81,6 +81,8 @@ struct tegra_gpio { ...@@ -81,6 +81,8 @@ struct tegra_gpio {
unsigned int *irq; unsigned int *irq;
const struct tegra_gpio_soc *soc; const struct tegra_gpio_soc *soc;
unsigned int num_irqs_per_bank;
unsigned int num_banks;
void __iomem *secure; void __iomem *secure;
void __iomem *base; void __iomem *base;
...@@ -594,6 +596,28 @@ static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio) ...@@ -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) static int tegra186_gpio_probe(struct platform_device *pdev)
{ {
unsigned int i, j, offset; unsigned int i, j, offset;
...@@ -608,7 +632,17 @@ static int tegra186_gpio_probe(struct platform_device *pdev) ...@@ -608,7 +632,17 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
gpio->soc = device_get_match_data(&pdev->dev); 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"); gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
if (IS_ERR(gpio->secure)) { if (IS_ERR(gpio->secure)) {
gpio->secure = devm_platform_ioremap_resource(pdev, 0); gpio->secure = devm_platform_ioremap_resource(pdev, 0);
...@@ -629,6 +663,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev) ...@@ -629,6 +663,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->num_irq = err; 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), gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq),
GFP_KERNEL); GFP_KERNEL);
if (!gpio->irq) if (!gpio->irq)
...@@ -642,9 +680,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev) ...@@ -642,9 +680,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->irq[i] = err; gpio->irq[i] = err;
} }
gpio->gpio.label = gpio->soc->name;
gpio->gpio.parent = &pdev->dev;
gpio->gpio.request = gpiochip_generic_request; gpio->gpio.request = gpiochip_generic_request;
gpio->gpio.free = gpiochip_generic_free; gpio->gpio.free = gpiochip_generic_free;
gpio->gpio.get_direction = tegra186_gpio_get_direction; gpio->gpio.get_direction = tegra186_gpio_get_direction;
...@@ -708,7 +743,30 @@ static int tegra186_gpio_probe(struct platform_device *pdev) ...@@ -708,7 +743,30 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
irq->parent_handler = tegra186_gpio_irq; irq->parent_handler = tegra186_gpio_irq;
irq->parent_handler_data = gpio; irq->parent_handler_data = gpio;
irq->num_parents = gpio->num_irq; 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); np = of_find_matching_node(NULL, tegra186_pmc_of_match);
if (np) { if (np) {
...@@ -719,8 +777,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev) ...@@ -719,8 +777,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
tegra186_gpio_init_route_mapping(gpio);
irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio, irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
sizeof(*irq->map), GFP_KERNEL); sizeof(*irq->map), GFP_KERNEL);
if (!irq->map) if (!irq->map)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment