drivers/irqchip/irq-ast2700-intc1.c

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

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-ast2700-intc1.c
Extension
.c
Size
7720 bytes
Lines
281
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 aspeed_intc1 {
	struct device				*dev;
	void __iomem				*base;
	raw_spinlock_t				intc_lock;
	struct irq_domain			*local;
	struct irq_domain			*upstream;
	struct aspeed_intc_interrupt_ranges	ranges;
};

static void aspeed_intc1_disable_int(struct aspeed_intc1 *intc1)
{
	for (int i = 0; i < INTC1_BANK_NUM; i++)
		writel(0, intc1->base + INTC1_IER + (INTC1_BANK_SIZE * i));
}

static void aspeed_intc1_irq_handler(struct irq_desc *desc)
{
	struct aspeed_intc1 *intc1 = irq_desc_get_handler_data(desc);
	struct irq_chip *chip = irq_desc_get_chip(desc);
	unsigned long bit, status;

	chained_irq_enter(chip, desc);

	for (int bank = 0; bank < INTC1_BANK_NUM; bank++) {
		status = readl(intc1->base + INTC1_ISR + (INTC1_BANK_SIZE * bank));
		if (!status)
			continue;

		for_each_set_bit(bit, &status, INTC1_IRQS_PER_BANK) {
			generic_handle_domain_irq(intc1->local, (bank * INTC1_IRQS_PER_BANK) + bit);
			writel(BIT(bit), intc1->base + INTC1_ISR + (INTC1_BANK_SIZE * bank));
		}
	}

	chained_irq_exit(chip, desc);
}

static void aspeed_intc1_irq_mask(struct irq_data *data)
{
	struct aspeed_intc1 *intc1 = irq_data_get_irq_chip_data(data);
	int bank = data->hwirq / INTC1_IRQS_PER_BANK;
	int bit = data->hwirq % INTC1_IRQS_PER_BANK;
	u32 ier;

	guard(raw_spinlock)(&intc1->intc_lock);
	ier = readl(intc1->base + INTC1_IER + (INTC1_BANK_SIZE * bank)) & ~BIT(bit);
	writel(ier, intc1->base + INTC1_IER + (INTC1_BANK_SIZE * bank));
}

static void aspeed_intc1_irq_unmask(struct irq_data *data)
{
	struct aspeed_intc1 *intc1 = irq_data_get_irq_chip_data(data);
	int bank = data->hwirq / INTC1_IRQS_PER_BANK;
	int bit = data->hwirq % INTC1_IRQS_PER_BANK;
	u32 ier;

	guard(raw_spinlock)(&intc1->intc_lock);
	ier = readl(intc1->base + INTC1_IER + (INTC1_BANK_SIZE * bank)) | BIT(bit);
	writel(ier, intc1->base + INTC1_IER + (INTC1_BANK_SIZE * bank));
}

static struct irq_chip aspeed_intc_chip = {
	.name		= "ASPEED INTC1",
	.irq_mask	= aspeed_intc1_irq_mask,
	.irq_unmask	= aspeed_intc1_irq_unmask,
};

static int aspeed_intc1_irq_domain_translate(struct irq_domain *domain,
					     struct irq_fwspec *fwspec,
					     unsigned long *hwirq,
					     unsigned int *type)
{
	if (fwspec->param_count != 1)
		return -EINVAL;

	*hwirq = fwspec->param[0];
	*type = IRQ_TYPE_LEVEL_HIGH;
	return 0;
}

static int aspeed_intc1_map_irq_domain(struct irq_domain *domain,
				       unsigned int irq,
				       irq_hw_number_t hwirq)
{
	irq_domain_set_info(domain, irq, hwirq, &aspeed_intc_chip,
			    domain->host_data, handle_level_irq, NULL, NULL);
	return 0;
}

/*

Annotation

Implementation Notes