drivers/irqchip/exynos-combiner.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/exynos-combiner.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/exynos-combiner.c
Extension
.c
Size
6809 bytes
Lines
275
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 combiner_chip_data {
	unsigned int hwirq_offset;
	unsigned int irq_mask;
	void __iomem *base;
	unsigned int parent_irq;
#ifdef CONFIG_PM
	u32 pm_save;
#endif
};

static struct combiner_chip_data *combiner_data;
static struct irq_domain *combiner_irq_domain;
static unsigned int max_nr = 20;

static inline void __iomem *combiner_base(struct irq_data *data)
{
	struct combiner_chip_data *combiner_data =
		irq_data_get_irq_chip_data(data);

	return combiner_data->base;
}

static void combiner_mask_irq(struct irq_data *data)
{
	u32 mask = 1 << (data->hwirq % 32);

	writel_relaxed(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
}

static void combiner_unmask_irq(struct irq_data *data)
{
	u32 mask = 1 << (data->hwirq % 32);

	writel_relaxed(mask, combiner_base(data) + COMBINER_ENABLE_SET);
}

static void combiner_handle_cascade_irq(struct irq_desc *desc)
{
	struct combiner_chip_data *chip_data = irq_desc_get_handler_data(desc);
	struct irq_chip *chip = irq_desc_get_chip(desc);
	unsigned int combiner_irq;
	unsigned long status;
	int ret;

	chained_irq_enter(chip, desc);

	status = readl_relaxed(chip_data->base + COMBINER_INT_STATUS);
	status &= chip_data->irq_mask;

	if (status == 0)
		goto out;

	combiner_irq = chip_data->hwirq_offset + __ffs(status);
	ret = generic_handle_domain_irq(combiner_irq_domain, combiner_irq);
	if (unlikely(ret))
		handle_bad_irq(desc);

 out:
	chained_irq_exit(chip, desc);
}

#ifdef CONFIG_SMP
static int combiner_set_affinity(struct irq_data *d,
				 const struct cpumask *mask_val, bool force)
{
	struct combiner_chip_data *chip_data = irq_data_get_irq_chip_data(d);
	struct irq_chip *chip = irq_get_chip(chip_data->parent_irq);
	struct irq_data *data = irq_get_irq_data(chip_data->parent_irq);

	if (chip && chip->irq_set_affinity)
		return chip->irq_set_affinity(data, mask_val, force);
	else
		return -EINVAL;
}
#endif

static struct irq_chip combiner_chip = {
	.name			= "COMBINER",
	.irq_mask		= combiner_mask_irq,
	.irq_unmask		= combiner_unmask_irq,
#ifdef CONFIG_SMP
	.irq_set_affinity	= combiner_set_affinity,
#endif
};

static void __init combiner_cascade_irq(struct combiner_chip_data *combiner_data,
					unsigned int irq)
{
	irq_set_chained_handler_and_data(irq, combiner_handle_cascade_irq,
					 combiner_data);

Annotation

Implementation Notes