drivers/irqchip/irq-ingenic.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-ingenic.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-ingenic.c
Extension
.c
Size
4000 bytes
Lines
161
Domain
Driver Families
Bucket
drivers/irqchip
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct ingenic_intc_data {
	void __iomem *base;
	struct irq_domain *domain;
	unsigned num_chips;
};

#define JZ_REG_INTC_STATUS	0x00
#define JZ_REG_INTC_MASK	0x04
#define JZ_REG_INTC_SET_MASK	0x08
#define JZ_REG_INTC_CLEAR_MASK	0x0c
#define JZ_REG_INTC_PENDING	0x10
#define CHIP_SIZE		0x20

static irqreturn_t intc_cascade(int irq, void *data)
{
	struct ingenic_intc_data *intc = irq_get_handler_data(irq);
	struct irq_domain *domain = intc->domain;
	struct irq_chip_generic *gc;
	uint32_t pending;
	unsigned i;

	for (i = 0; i < intc->num_chips; i++) {
		gc = irq_get_domain_generic_chip(domain, i * 32);

		pending = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
		if (!pending)
			continue;

		while (pending) {
			int bit = __fls(pending);

			generic_handle_domain_irq(domain, bit + (i * 32));
			pending &= ~BIT(bit);
		}
	}

	return IRQ_HANDLED;
}

static int __init ingenic_intc_of_init(struct device_node *node,
				       unsigned num_chips)
{
	struct ingenic_intc_data *intc;
	struct irq_chip_generic *gc;
	struct irq_chip_type *ct;
	struct irq_domain *domain;
	int parent_irq, err = 0;
	unsigned i;

	intc = kzalloc_obj(*intc);
	if (!intc) {
		err = -ENOMEM;
		goto out_err;
	}

	parent_irq = irq_of_parse_and_map(node, 0);
	if (!parent_irq) {
		err = -EINVAL;
		goto out_free;
	}

	err = irq_set_handler_data(parent_irq, intc);
	if (err)
		goto out_unmap_irq;

	intc->num_chips = num_chips;
	intc->base = of_iomap(node, 0);
	if (!intc->base) {
		err = -ENODEV;
		goto out_unmap_irq;
	}

	domain = irq_domain_create_linear(of_fwnode_handle(node), num_chips * 32,
					  &irq_generic_chip_ops, NULL);
	if (!domain) {
		err = -ENOMEM;
		goto out_unmap_base;
	}

	intc->domain = domain;

	err = irq_alloc_domain_generic_chips(domain, 32, 1, "INTC",
					     handle_level_irq, 0,
					     IRQ_NOPROBE | IRQ_LEVEL, 0);
	if (err)
		goto out_domain_remove;

	for (i = 0; i < num_chips; i++) {
		gc = irq_get_domain_generic_chip(domain, i * 32);

Annotation

Implementation Notes