drivers/irqchip/irq-ixp4xx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-ixp4xx.c
Extension
.c
Size
7684 bytes
Lines
285
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 ixp4xx_irq {
	void __iomem *irqbase;
	bool is_356;
	struct irq_chip irqchip;
	struct irq_domain *domain;
};

/* Local static state container */
static struct ixp4xx_irq ixirq;

/* GPIO Clocks */
#define IXP4XX_GPIO_CLK_0		14
#define IXP4XX_GPIO_CLK_1		15

static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type)
{
	/* All are level active high (asserted) here */
	if (type != IRQ_TYPE_LEVEL_HIGH)
		return -EINVAL;
	return 0;
}

static void ixp4xx_irq_mask(struct irq_data *d)
{
	struct ixp4xx_irq *ixi = irq_data_get_irq_chip_data(d);
	u32 val;

	if (ixi->is_356 && d->hwirq >= 32) {
		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR2);
		val &= ~BIT(d->hwirq - 32);
		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR2);
	} else {
		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR);
		val &= ~BIT(d->hwirq);
		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR);
	}
}

/*
 * Level triggered interrupts on GPIO lines can only be cleared when the
 * interrupt condition disappears.
 */
static void ixp4xx_irq_unmask(struct irq_data *d)
{
	struct ixp4xx_irq *ixi = irq_data_get_irq_chip_data(d);
	u32 val;

	if (ixi->is_356 && d->hwirq >= 32) {
		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR2);
		val |= BIT(d->hwirq - 32);
		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR2);
	} else {
		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR);
		val |= BIT(d->hwirq);
		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR);
	}
}

static void __exception_irq_entry ixp4xx_handle_irq(struct pt_regs *regs)
{
	struct ixp4xx_irq *ixi = &ixirq;
	unsigned long status;
	int i;

	status = __raw_readl(ixi->irqbase + IXP4XX_ICIP);
	for_each_set_bit(i, &status, 32)
		generic_handle_domain_irq(ixi->domain, i);

	/*
	 * IXP465/IXP435 has an upper IRQ status register
	 */
	if (ixi->is_356) {
		status = __raw_readl(ixi->irqbase + IXP4XX_ICIP2);
		for_each_set_bit(i, &status, 32)
			generic_handle_domain_irq(ixi->domain, i + 32);
	}
}

static int ixp4xx_irq_domain_translate(struct irq_domain *domain,
				       struct irq_fwspec *fwspec,
				       unsigned long *hwirq,
				       unsigned int *type)
{
	/* We support standard DT translation */
	if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
		*hwirq = fwspec->param[0];
		*type = fwspec->param[1];
		return 0;
	}

Annotation

Implementation Notes