drivers/irqchip/irq-ingenic-tcu.c

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

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-ingenic-tcu.c
Extension
.c
Size
5112 bytes
Lines
184
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_tcu {
	struct regmap *map;
	struct clk *clk;
	struct irq_domain *domain;
	unsigned int nb_parent_irqs;
	u32 parent_irqs[3];
};

static void ingenic_tcu_intc_cascade(struct irq_desc *desc)
{
	struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
	struct irq_domain *domain = irq_desc_get_handler_data(desc);
	struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
	struct regmap *map = gc->private;
	uint32_t irq_reg, irq_mask;
	unsigned long bits;
	unsigned int i;

	regmap_read(map, TCU_REG_TFR, &irq_reg);
	regmap_read(map, TCU_REG_TMR, &irq_mask);

	chained_irq_enter(irq_chip, desc);

	irq_reg &= ~irq_mask;
	bits = irq_reg;

	for_each_set_bit(i, &bits, 32)
		generic_handle_domain_irq(domain, i);

	chained_irq_exit(irq_chip, desc);
}

static void ingenic_tcu_gc_unmask_enable_reg(struct irq_data *d)
{
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
	struct irq_chip_type *ct = irq_data_get_chip_type(d);
	struct regmap *map = gc->private;
	u32 mask = d->mask;

	guard(raw_spinlock)(&gc->lock);
	regmap_write(map, ct->regs.ack, mask);
	regmap_write(map, ct->regs.enable, mask);
	*ct->mask_cache |= mask;
}

static void ingenic_tcu_gc_mask_disable_reg(struct irq_data *d)
{
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
	struct irq_chip_type *ct = irq_data_get_chip_type(d);
	struct regmap *map = gc->private;
	u32 mask = d->mask;

	guard(raw_spinlock)(&gc->lock);
	regmap_write(map, ct->regs.disable, mask);
	*ct->mask_cache &= ~mask;
}

static void ingenic_tcu_gc_mask_disable_reg_and_ack(struct irq_data *d)
{
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
	struct irq_chip_type *ct = irq_data_get_chip_type(d);
	struct regmap *map = gc->private;
	u32 mask = d->mask;

	guard(raw_spinlock)(&gc->lock);
	regmap_write(map, ct->regs.ack, mask);
	regmap_write(map, ct->regs.disable, mask);
}

static int __init ingenic_tcu_irq_init(struct device_node *np,
				       struct device_node *parent)
{
	struct irq_chip_generic *gc;
	struct irq_chip_type *ct;
	struct ingenic_tcu *tcu;
	struct regmap *map;
	unsigned int i;
	int ret, irqs;

	map = device_node_to_regmap(np);
	if (IS_ERR(map))
		return PTR_ERR(map);

	tcu = kzalloc_obj(*tcu);
	if (!tcu)
		return -ENOMEM;

	tcu->map = map;

	irqs = of_property_count_elems_of_size(np, "interrupts", sizeof(u32));

Annotation

Implementation Notes