static int __init tegra_ictlr_init()

in irq-tegra.c [275:355]


static int __init tegra_ictlr_init(struct device_node *node,
				   struct device_node *parent)
{
	struct irq_domain *parent_domain, *domain;
	const struct of_device_id *match;
	const struct tegra_ictlr_soc *soc;
	unsigned int i;
	int err;

	if (!parent) {
		pr_err("%pOF: no parent, giving up\n", node);
		return -ENODEV;
	}

	parent_domain = irq_find_host(parent);
	if (!parent_domain) {
		pr_err("%pOF: unable to obtain parent domain\n", node);
		return -ENXIO;
	}

	match = of_match_node(ictlr_matches, node);
	if (!match)		/* Should never happen... */
		return -ENODEV;

	soc = match->data;

	lic = kzalloc(sizeof(*lic), GFP_KERNEL);
	if (!lic)
		return -ENOMEM;

	for (i = 0; i < TEGRA_MAX_NUM_ICTLRS; i++) {
		void __iomem *base;

		base = of_iomap(node, i);
		if (!base)
			break;

		lic->base[i] = base;

		/* Disable all interrupts */
		writel_relaxed(~0UL, base + ICTLR_CPU_IER_CLR);
		/* All interrupts target IRQ */
		writel_relaxed(0, base + ICTLR_CPU_IEP_CLASS);

		num_ictlrs++;
	}

	if (!num_ictlrs) {
		pr_err("%pOF: no valid regions, giving up\n", node);
		err = -ENOMEM;
		goto out_free;
	}

	WARN(num_ictlrs != soc->num_ictlrs,
	     "%pOF: Found %u interrupt controllers in DT; expected %u.\n",
	     node, num_ictlrs, soc->num_ictlrs);


	domain = irq_domain_add_hierarchy(parent_domain, 0, num_ictlrs * 32,
					  node, &tegra_ictlr_domain_ops,
					  lic);
	if (!domain) {
		pr_err("%pOF: failed to allocated domain\n", node);
		err = -ENOMEM;
		goto out_unmap;
	}

	tegra_ictlr_syscore_init();

	pr_info("%pOF: %d interrupts forwarded to %pOF\n",
		node, num_ictlrs * 32, parent);

	return 0;

out_unmap:
	for (i = 0; i < num_ictlrs; i++)
		iounmap(lic->base[i]);
out_free:
	kfree(lic);
	return err;
}