1/* 2 * Copyright (C) 2012 Thomas Petazzoni 3 * 4 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 5 * 6 * This file is licensed under the terms of the GNU General Public 7 * License version 2. This program is licensed "as is" without any 8 * warranty of any kind, whether express or implied. 9 */ 10 11#include <linux/acpi.h> 12#include <linux/init.h> 13#include <linux/of_device.h> 14#include <linux/of_irq.h> 15#include <linux/irqchip.h> 16#include <linux/platform_device.h> 17 18#ifdef CONFIG_IRQCHIP_XILINX_INTC_MODULE_SUPPORT_EXPERIMENTAL 19struct platform_irqchip_instance { 20 of_irq_init_cb_t irq_init_cb; 21 of_irq_remove_cb_t irq_remove_cb; 22 struct device_node *parent_node; 23}; 24#endif 25 26/* 27 * This special of_device_id is the sentinel at the end of the 28 * of_device_id[] array of all irqchips. It is automatically placed at 29 * the end of the array by the linker, thanks to being part of a 30 * special section. 31 */ 32static const struct of_device_id 33irqchip_of_match_end __used __section("__irqchip_of_table_end"); 34 35extern struct of_device_id __irqchip_of_table[]; 36 37void __init irqchip_init(void) 38{ 39 of_irq_init(__irqchip_of_table); 40 acpi_probe_device_table(irqchip); 41} 42 43#ifndef CONFIG_IRQCHIP_XILINX_INTC_MODULE_SUPPORT_EXPERIMENTAL 44int platform_irqchip_probe(struct platform_device *pdev) 45{ 46 struct device_node *np = pdev->dev.of_node; 47 struct device_node *par_np = of_irq_find_parent(np); 48 of_irq_init_cb_t irq_init_cb = of_device_get_match_data(&pdev->dev); 49 50 if (!irq_init_cb) 51 return -EINVAL; 52 53 if (par_np == np) 54 par_np = NULL; 55 56 /* 57 * If there's a parent interrupt controller and none of the parent irq 58 * domains have been registered, that means the parent interrupt 59 * controller has not been initialized yet. it's not time for this 60 * interrupt controller to initialize. So, defer probe of this 61 * interrupt controller. The actual initialization callback of this 62 * interrupt controller can check for specific domains as necessary. 63 */ 64 if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY)) 65 return -EPROBE_DEFER; 66 67 return irq_init_cb(np, par_np); 68} 69EXPORT_SYMBOL_GPL(platform_irqchip_probe); 70#else 71int platform_irqchip_probe(struct platform_device *pdev) 72{ 73 struct platform_irqchip_instance *irqchip; 74 const struct irqc_init_remove_funps *irqchip_funps; 75 struct device_node *np = pdev->dev.of_node; 76 struct device_node *par_np = of_irq_find_parent(np); 77 78 irqchip = devm_kzalloc(&pdev->dev, sizeof(*irqchip), GFP_KERNEL); 79 if (!irqchip) 80 return -ENOMEM; 81 82 platform_set_drvdata(pdev, irqchip); 83 84 irqchip_funps = of_device_get_match_data(&pdev->dev); 85 irqchip->irq_init_cb = irqchip_funps->irqchip_initp; 86 irqchip->irq_remove_cb = irqchip_funps->irqchip_removep; 87 irqchip->parent_node = par_np; 88 89 if (!irqchip->irq_init_cb) 90 return -EINVAL; 91 92 if (par_np == np) 93 par_np = NULL; 94 95 /* 96 * If there's a parent interrupt controller and none of the parent irq 97 * domains have been registered, that means the parent interrupt 98 * controller has not been initialized yet. it's not time for this 99 * interrupt controller to initialize. So, defer probe of this 100 * interrupt controller. The actual initialization callback of this 101 * interrupt controller can check for specific domains as necessary. 102 */ 103 if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY)) 104 return -EPROBE_DEFER; 105 106 return irqchip->irq_init_cb(np, par_np); 107} 108EXPORT_SYMBOL_GPL(platform_irqchip_probe); 109 110int platform_irqchip_remove(struct platform_device *pdev) 111{ 112 struct device_node *np = pdev->dev.of_node; 113 struct platform_irqchip_instance *irqchip = platform_get_drvdata(pdev); 114 struct device_node *par_np = irqchip->parent_node; 115 116 if (!irqchip->irq_remove_cb) 117 return -EINVAL; 118 119 if (par_np == np) 120 par_np = NULL; 121 122 return irqchip->irq_remove_cb(np, par_np); 123} 124EXPORT_SYMBOL_GPL(platform_irqchip_remove); 125#endif 126