Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8daeffb0 authored by Barry Song's avatar Barry Song Committed by Linus Walleij
Browse files

pinctrl: sirf: use only one irq_domain for the whole device node



in sirfsoc gpio probe(), we create 5 irq_domains for 5 gpio banks. but
in irq_create_of_mapping() of irqchip core level, irq_find_host() can
only return the 1st irq_domain attached the pinctrl dt device node as
we can see from the codes:

unsigned int irq_create_of_mapping(struct device_node *controller,
				   const u32 *intspec, unsigned int intsize)
{
	struct irq_domain *domain;
	...
	domain = controller ? irq_find_host(controller) : irq_default_domain;
}

struct irq_domain *irq_find_host(struct device_node *node)
{
	struct irq_domain *h, *found = NULL;
	int rc;

	/* We might want to match the legacy controller last since
	 * it might potentially be set to match all interrupts in
	 * the absence of a device node. This isn't a problem so far
	 * yet though...
	 */
	mutex_lock(&irq_domain_mutex);
	list_for_each_entry(h, &irq_domain_list, link) {
		if (h->ops->match)
			rc = h->ops->match(h, node);
		else
			rc = (h->of_node != NULL) && (h->of_node == node);

		if (rc) {
			found = h;
			break;
		}
	}
	mutex_unlock(&irq_domain_mutex);
	return found;
}

for sirfsoc, the 1st irq_domain attached to the device_node(controller) only
can do linear for the 1st 32 gpios. so for devices who use gpio hwirq above
32 and put the information in dt like:
                                tangoc-ts@5c{
                                        compatible = "pixcir,tangoc-ts";
+                                       interrupt-parent = <&gpio>;
+                                       interrupts = <34 0>;
                                };

we will fail to get the virq for these devices as hwirq will be bigger than
domain->revmap_data.linear.size in:
unsigned int irq_linear_revmap(struct irq_domain *domain,
			       irq_hw_number_t hwirq)
{

	/* Check revmap bounds; complain if exceeded */
	if (WARN_ON(hwirq >= domain->revmap_data.linear.size))
		return 0;

	return domain->revmap_data.linear.revmap[hwirq];
}

this patch drops redundant irq_domain and keep only one to fix the problem.

Signed-off-by: default avatarBarry Song <Baohua.Song@csr.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent ad5d25fe
Loading
Loading
Loading
Loading
+15 −11
Original line number Diff line number Diff line
@@ -468,7 +468,8 @@ static inline int sirfsoc_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
	struct sirfsoc_gpio_bank *bank = container_of(to_of_mm_gpio_chip(chip),
		struct sirfsoc_gpio_bank, chip);

	return irq_create_mapping(bank->domain, offset);
	return irq_create_mapping(bank->domain, offset + bank->id *
		SIRFSOC_GPIO_BANK_SIZE);
}

static inline int sirfsoc_gpio_to_offset(unsigned int gpio)
@@ -629,7 +630,8 @@ static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc)
		if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) {
			pr_debug("%s: gpio id %d idx %d happens\n",
				__func__, bank->id, idx);
			generic_handle_irq(irq_find_mapping(bank->domain, idx));
			generic_handle_irq(irq_find_mapping(bank->domain, idx +
					bank->id * SIRFSOC_GPIO_BANK_SIZE));
		}

		idx++;
@@ -786,7 +788,7 @@ static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,

	irq_set_chip(irq, &sirfsoc_irq_chip);
	irq_set_handler(irq, handle_level_irq);
	irq_set_chip_data(irq, bank);
	irq_set_chip_data(irq, bank + hwirq / SIRFSOC_GPIO_BANK_SIZE);
	set_irq_flags(irq, IRQF_VALID);

	return 0;
@@ -835,6 +837,7 @@ static int sirfsoc_gpio_probe(struct device_node *np)
	struct sirfsoc_gpio_bank *bank;
	void __iomem *regs;
	struct platform_device *pdev;
	struct irq_domain *domain;
	bool is_marco = false;

	u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS];
@@ -850,6 +853,14 @@ static int sirfsoc_gpio_probe(struct device_node *np)
	if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
		is_marco = 1;

	domain = irq_domain_add_linear(np, SIRFSOC_GPIO_BANK_SIZE * SIRFSOC_GPIO_NO_OF_BANKS,
		&sirfsoc_gpio_irq_simple_ops, sgpio_bank);
	if (!domain) {
		pr_err("%s: Failed to create irqdomain\n", np->full_name);
			err = -ENOSYS;
		goto out;
	}

	for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
		bank = &sgpio_bank[i];
		spin_lock_init(&bank->lock);
@@ -882,14 +893,7 @@ static int sirfsoc_gpio_probe(struct device_node *np)
			goto out;
		}

		bank->domain = irq_domain_add_linear(np, SIRFSOC_GPIO_BANK_SIZE,
						&sirfsoc_gpio_irq_simple_ops, bank);

		if (!bank->domain) {
			pr_err("%s: Failed to create irqdomain\n", np->full_name);
			err = -ENOSYS;
			goto out;
		}
		bank->domain = domain;

		irq_set_chained_handler(bank->parent_irq, sirfsoc_gpio_handle_irq);
		irq_set_handler_data(bank->parent_irq, bank);