diff options
-rw-r--r-- | drivers/irqchip/irqchip.c | 29 | ||||
-rw-r--r-- | include/linux/irqchip.h | 23 |
2 files changed, 52 insertions, 0 deletions
diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c index 2b35e68bea82..1bb0e36c2bf3 100644 --- a/drivers/irqchip/irqchip.c +++ b/drivers/irqchip/irqchip.c @@ -10,8 +10,10 @@ #include <linux/acpi.h> #include <linux/init.h> +#include <linux/of_device.h> #include <linux/of_irq.h> #include <linux/irqchip.h> +#include <linux/platform_device.h> /* * This special of_device_id is the sentinel at the end of the @@ -29,3 +31,30 @@ void __init irqchip_init(void) of_irq_init(__irqchip_of_table); acpi_probe_device_table(irqchip); } + +int platform_irqchip_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *par_np = of_irq_find_parent(np); + of_irq_init_cb_t irq_init_cb = of_device_get_match_data(&pdev->dev); + + if (!irq_init_cb) + return -EINVAL; + + if (par_np == np) + par_np = NULL; + + /* + * If there's a parent interrupt controller and none of the parent irq + * domains have been registered, that means the parent interrupt + * controller has not been initialized yet. it's not time for this + * interrupt controller to initialize. So, defer probe of this + * interrupt controller. The actual initialization callback of this + * interrupt controller can check for specific domains as necessary. + */ + if (par_np && !irq_find_matching_host(np, DOMAIN_BUS_ANY)) + return -EPROBE_DEFER; + + return irq_init_cb(np, par_np); +} +EXPORT_SYMBOL_GPL(platform_irqchip_probe); diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h index 447f22880a69..8e754d8b8155 100644 --- a/include/linux/irqchip.h +++ b/include/linux/irqchip.h @@ -13,6 +13,7 @@ #include <linux/acpi.h> #include <linux/of.h> +#include <linux/platform_device.h> /* * This macro must be used by the different irqchip drivers to declare @@ -26,6 +27,28 @@ */ #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn) +extern int platform_irqchip_probe(struct platform_device *pdev); + +#define IRQCHIP_PLATFORM_DRIVER_BEGIN(drv_name) \ +static const struct of_device_id drv_name##_irqchip_match_table[] = { + +#define IRQCHIP_MATCH(compat, fn) { .compatible = compat, .data = fn }, + +#define IRQCHIP_PLATFORM_DRIVER_END(drv_name) \ + {}, \ +}; \ +MODULE_DEVICE_TABLE(of, drv_name##_irqchip_match_table); \ +static struct platform_driver drv_name##_driver = { \ + .probe = platform_irqchip_probe, \ + .driver = { \ + .name = #drv_name, \ + .owner = THIS_MODULE, \ + .of_match_table = drv_name##_irqchip_match_table, \ + .suppress_bind_attrs = true, \ + }, \ +}; \ +builtin_platform_driver(drv_name##_driver) + /* * This macro must be used by the different irqchip drivers to declare * the association between their version and their initialization function. |