drivers/irqchip/irq-pic32-evic.c

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

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-pic32-evic.c
Extension
.c
Size
8373 bytes
Lines
324
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 evic_chip_data {
	u32 irq_types[NR_IRQS];
	u32 ext_irqs[8];
};

static struct irq_domain *evic_irq_domain;
static void __iomem *evic_base;

#ifdef CONFIG_MIPS
asmlinkage void __weak plat_irq_dispatch(void)
{
	unsigned int hwirq;

	hwirq = readl(evic_base + REG_INTSTAT) & 0xFF;
	do_domain_IRQ(evic_irq_domain, hwirq);
}
#else
static __maybe_unused void (*board_bind_eic_interrupt)(int irq, int regset);
#endif

static struct evic_chip_data *irqd_to_priv(struct irq_data *data)
{
	return (struct evic_chip_data *)data->domain->host_data;
}

static int pic32_set_ext_polarity(int bit, u32 type)
{
	/*
	 * External interrupts can be either edge rising or edge falling,
	 * but not both.
	 */
	switch (type) {
	case IRQ_TYPE_EDGE_RISING:
		writel(BIT(bit), evic_base + PIC32_SET(REG_INTCON));
		break;
	case IRQ_TYPE_EDGE_FALLING:
		writel(BIT(bit), evic_base + PIC32_CLR(REG_INTCON));
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int pic32_set_type_edge(struct irq_data *data,
			       unsigned int flow_type)
{
	struct evic_chip_data *priv = irqd_to_priv(data);
	int ret;
	int i;

	if (!(flow_type & IRQ_TYPE_EDGE_BOTH))
		return -EBADR;

	/* set polarity for external interrupts only */
	for (i = 0; i < ARRAY_SIZE(priv->ext_irqs); i++) {
		if (priv->ext_irqs[i] == data->hwirq) {
			ret = pic32_set_ext_polarity(i, flow_type);
			if (ret)
				return ret;
		}
	}

	irqd_set_trigger_type(data, flow_type);

	return IRQ_SET_MASK_OK;
}

static void pic32_bind_evic_interrupt(int irq, int set)
{
	writel(set, evic_base + REG_OFF_OFFSET + irq * 4);
}

static void pic32_set_irq_priority(int irq, int priority)
{
	u32 reg, shift;

	reg = irq / 4;
	shift = (irq % 4) * 8;

	writel(PRIORITY_MASK << shift,
		evic_base + PIC32_CLR(REG_IPC_OFFSET + reg * 0x10));
	writel(priority << shift,
		evic_base + PIC32_SET(REG_IPC_OFFSET + reg * 0x10));
}

#define IRQ_REG_MASK(_hwirq, _reg, _mask)		       \
	do {						       \
		_reg = _hwirq / 32;			       \

Annotation

Implementation Notes