drivers/irqchip/irq-mtk-sysirq.c

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

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-mtk-sysirq.c
Extension
.c
Size
5919 bytes
Lines
235
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 mtk_sysirq_chip_data {
	raw_spinlock_t lock;
	u32 nr_intpol_bases;
	void __iomem **intpol_bases;
	u32 *intpol_words;
	u8 *intpol_idx;
	u16 *which_word;
};

static int mtk_sysirq_set_type(struct irq_data *data, unsigned int type)
{
	irq_hw_number_t hwirq = data->hwirq;
	struct mtk_sysirq_chip_data *chip_data = data->chip_data;
	u8 intpol_idx = chip_data->intpol_idx[hwirq];
	void __iomem *base;
	u32 offset, reg_index, value;
	unsigned long flags;
	int ret;

	base = chip_data->intpol_bases[intpol_idx];
	reg_index = chip_data->which_word[hwirq];
	offset = hwirq & 0x1f;

	raw_spin_lock_irqsave(&chip_data->lock, flags);
	value = readl_relaxed(base + reg_index * 4);
	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_EDGE_FALLING) {
		if (type == IRQ_TYPE_LEVEL_LOW)
			type = IRQ_TYPE_LEVEL_HIGH;
		else
			type = IRQ_TYPE_EDGE_RISING;
		value |= (1 << offset);
	} else {
		value &= ~(1 << offset);
	}

	writel_relaxed(value, base + reg_index * 4);

	data = data->parent_data;
	ret = data->chip->irq_set_type(data, type);
	raw_spin_unlock_irqrestore(&chip_data->lock, flags);
	return ret;
}

static struct irq_chip mtk_sysirq_chip = {
	.name			= "MT_SYSIRQ",
	.irq_mask		= irq_chip_mask_parent,
	.irq_unmask		= irq_chip_unmask_parent,
	.irq_eoi		= irq_chip_eoi_parent,
	.irq_set_type		= mtk_sysirq_set_type,
	.irq_retrigger		= irq_chip_retrigger_hierarchy,
	.irq_set_affinity	= irq_chip_set_affinity_parent,
	.flags			= IRQCHIP_SKIP_SET_WAKE,
};

static int mtk_sysirq_domain_translate(struct irq_domain *d,
				       struct irq_fwspec *fwspec,
				       unsigned long *hwirq,
				       unsigned int *type)
{
	if (is_of_node(fwspec->fwnode)) {
		if (fwspec->param_count != 3)
			return -EINVAL;

		/* No PPI should point to this domain */
		if (fwspec->param[0] != 0)
			return -EINVAL;

		*hwirq = fwspec->param[1];
		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
		return 0;
	}

	return -EINVAL;
}

static int mtk_sysirq_domain_alloc(struct irq_domain *domain, unsigned int virq,
				   unsigned int nr_irqs, void *arg)
{
	int i;
	irq_hw_number_t hwirq;
	struct irq_fwspec *fwspec = arg;
	struct irq_fwspec gic_fwspec = *fwspec;

	if (fwspec->param_count != 3)
		return -EINVAL;

	/* sysirq doesn't support PPI */
	if (fwspec->param[0])
		return -EINVAL;

Annotation

Implementation Notes