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

Commit 56b2d70b authored by Lina Iyer's avatar Lina Iyer
Browse files

drivers: irqchip: pdc: check for valid GPIO interrupts



PDC is the parent of TLMM to enable wakeup from GPIO. To achieve this,
PDC irqchip exports a irqdomain specifically for GPIOS. But not all
GPIOs are routed to the PDC. So when a driver requests a GPIO, the TLMM
driver must check in its map to see if a corresponding PDC interrupt
exits for the GPIO.

If it does, TLMM will translate to the PDC interrupt and request an
interrupt to be allocated at the PDC. If the GPIO is not mapped to a PDC
line, it still has to request the PDC to allocate an interrupt in the
irqdomain. This is necessary as PDC alloc will setup the irqchip on the
irqdomain. Failing to do so will result in an exception when calling the
_set_parent functions on the irqchip.

Set up GPIO_NO_WAKE_IRQ as the parent interrupt of a non-wakeup capable
GPIOs.

Change-Id: I58f1ed0cc6daa50aec2d40bf38c1f645619a1021
Signed-off-by: default avatarLina Iyer <ilina@codeaurora.org>
parent 2c274e13
Loading
Loading
Loading
Loading
+25 −11
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@
#define IRQ_ENABLE_BANK		0x10
#define IRQ_i_CFG		0x110

#define PDC_NO_PARENT_IRQ	~0UL

struct pdc_pin_region {
	u32 pin_base;
	u32 parent_base;
@@ -66,12 +68,18 @@ static void pdc_enable_intr(struct irq_data *d, bool on)

static void qcom_pdc_gic_mask(struct irq_data *d)
{
	if (d->hwirq == GPIO_NO_WAKE_IRQ)
		return;

	pdc_enable_intr(d, false);
	irq_chip_mask_parent(d);
}

static void qcom_pdc_gic_unmask(struct irq_data *d)
{
	if (d->hwirq == GPIO_NO_WAKE_IRQ)
		return;

	pdc_enable_intr(d, true);
	irq_chip_unmask_parent(d);
}
@@ -115,6 +123,9 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
	int pin_out = d->hwirq;
	enum pdc_irq_config_bits pdc_type;

	if (pin_out == GPIO_NO_WAKE_IRQ)
		return 0;

	switch (type) {
	case IRQ_TYPE_EDGE_RISING:
		pdc_type = PDC_EDGE_RISING;
@@ -170,7 +181,7 @@ static irq_hw_number_t get_parent_hwirq(int pin)
			return (region->parent_base + pin - region->pin_base);
	}

	return ~0UL;
	return PDC_NO_PARENT_IRQ;
}

static int qcom_pdc_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
@@ -199,17 +210,17 @@ static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq,

	ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type);
	if (ret)
		return -EINVAL;

	parent_hwirq = get_parent_hwirq(hwirq);
	if (parent_hwirq == ~0UL)
		return -EINVAL;
		return ret;

	ret  = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
					     &qcom_pdc_gic_chip, NULL);
	if (ret)
		return ret;

	parent_hwirq = get_parent_hwirq(hwirq);
	if (parent_hwirq == PDC_NO_PARENT_IRQ)
		return 0;

	if (type & IRQ_TYPE_EDGE_BOTH)
		type = IRQ_TYPE_EDGE_RISING;

@@ -244,17 +255,20 @@ static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq,

	ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type);
	if (ret)
		return -EINVAL;

	parent_hwirq = get_parent_hwirq(hwirq);
	if (parent_hwirq == ~0UL)
		return -EINVAL;
		return ret;

	ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
					    &qcom_pdc_gic_chip, NULL);
	if (ret)
		return ret;

	if (hwirq == GPIO_NO_WAKE_IRQ)
		return 0;

	parent_hwirq = get_parent_hwirq(hwirq);
	if (parent_hwirq == PDC_NO_PARENT_IRQ)
		return 0;

	qcom_fwspec->mask = true;

	if (type & IRQ_TYPE_EDGE_BOTH)
+2 −0
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@

#include <linux/irqdomain.h>

#define GPIO_NO_WAKE_IRQ	~0U

/**
 * struct qcom_irq_fwspec - qcom specific irq fwspec wrapper
 * @fwspec: irq fwspec