Skip to content

Commit

Permalink
irqchip/exiu: Implement ACPI support
Browse files Browse the repository at this point in the history
Expose the existing EXIU hierarchical irqchip domain code to permit
the interrupt controller to be used as the irqchip component of a
GPIO controller on ACPI systems, or as the target of ordinary
interrupt resources.

Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
  • Loading branch information
Ard Biesheuvel authored and Marc Zyngier committed May 28, 2019
1 parent 0444638 commit 3d090a3
Showing 1 changed file with 68 additions and 8 deletions.
76 changes: 68 additions & 8 deletions drivers/irqchip/irq-sni-exiu.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>

#include <dt-bindings/interrupt-controller/arm-gic.h>

Expand Down Expand Up @@ -134,9 +135,13 @@ static int exiu_domain_translate(struct irq_domain *domain,

*hwirq = fwspec->param[1] - info->spi_base;
*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
return 0;
} else {
if (fwspec->param_count != 2)
return -EINVAL;
*hwirq = fwspec->param[0];
*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
}
return -EINVAL;
return 0;
}

static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
Expand All @@ -147,16 +152,21 @@ static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
struct exiu_irq_data *info = dom->host_data;
irq_hw_number_t hwirq;

if (fwspec->param_count != 3)
return -EINVAL; /* Not GIC compliant */
if (fwspec->param[0] != GIC_SPI)
return -EINVAL; /* No PPI should point to this domain */
parent_fwspec = *fwspec;
if (is_of_node(dom->parent->fwnode)) {
if (fwspec->param_count != 3)
return -EINVAL; /* Not GIC compliant */
if (fwspec->param[0] != GIC_SPI)
return -EINVAL; /* No PPI should point to this domain */

hwirq = fwspec->param[1] - info->spi_base;
} else {
hwirq = fwspec->param[0];
parent_fwspec.param[0] = hwirq + info->spi_base + 32;
}
WARN_ON(nr_irqs != 1);
hwirq = fwspec->param[1] - info->spi_base;
irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info);

parent_fwspec = *fwspec;
parent_fwspec.fwnode = dom->parent->fwnode;
return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec);
}
Expand Down Expand Up @@ -245,3 +255,53 @@ static int __init exiu_dt_init(struct device_node *node,
return -ENOMEM;
}
IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_dt_init);

#ifdef CONFIG_ACPI
static int exiu_acpi_probe(struct platform_device *pdev)
{
struct irq_domain *domain;
struct exiu_irq_data *data;
struct resource *res;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to parse memory resource\n");
return -ENXIO;
}

data = exiu_init(dev_fwnode(&pdev->dev), res);
if (IS_ERR(data))
return PTR_ERR(data);

domain = acpi_irq_create_hierarchy(0, NUM_IRQS, dev_fwnode(&pdev->dev),
&exiu_domain_ops, data);
if (!domain) {
dev_err(&pdev->dev, "failed to create IRQ domain\n");
goto out_unmap;
}

dev_info(&pdev->dev, "%d interrupts forwarded\n", NUM_IRQS);

return 0;

out_unmap:
iounmap(data->base);
kfree(data);
return -ENOMEM;
}

static const struct acpi_device_id exiu_acpi_ids[] = {
{ "SCX0008" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(acpi, exiu_acpi_ids);

static struct platform_driver exiu_driver = {
.driver = {
.name = "exiu",
.acpi_match_table = exiu_acpi_ids,
},
.probe = exiu_acpi_probe,
};
builtin_platform_driver(exiu_driver);
#endif

0 comments on commit 3d090a3

Please sign in to comment.