drivers/irqchip/irq-sun6i-r.c

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

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-sun6i-r.c
Extension
.c
Size
12004 bytes
Lines
386
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 sun6i_r_intc_variant {
	u32		first_mux_irq;
	u32		nr_mux_irqs;
	u32		mux_valid[BITS_TO_U32(SUN6I_NR_MUX_BITS)];
};

static void __iomem *base;
static irq_hw_number_t nmi_hwirq;
static DECLARE_BITMAP(wake_irq_enabled, SUN6I_NR_TOP_LEVEL_IRQS);
static DECLARE_BITMAP(wake_mux_enabled, SUN6I_NR_MUX_BITS);
static DECLARE_BITMAP(wake_mux_valid, SUN6I_NR_MUX_BITS);

static void sun6i_r_intc_ack_nmi(void)
{
	writel_relaxed(SUN6I_NMI_BIT, base + SUN6I_IRQ_PENDING(0));
}

static void sun6i_r_intc_nmi_ack(struct irq_data *data)
{
	if (irqd_get_trigger_type(data) & IRQ_TYPE_EDGE_BOTH)
		sun6i_r_intc_ack_nmi();
	else
		data->chip_data = SUN6I_NMI_NEEDS_ACK;
}

static void sun6i_r_intc_nmi_eoi(struct irq_data *data)
{
	/* For oneshot IRQs, delay the ack until the IRQ is unmasked. */
	if (data->chip_data == SUN6I_NMI_NEEDS_ACK && !irqd_irq_masked(data)) {
		data->chip_data = NULL;
		sun6i_r_intc_ack_nmi();
	}

	irq_chip_eoi_parent(data);
}

static void sun6i_r_intc_nmi_unmask(struct irq_data *data)
{
	if (data->chip_data == SUN6I_NMI_NEEDS_ACK) {
		data->chip_data = NULL;
		sun6i_r_intc_ack_nmi();
	}

	irq_chip_unmask_parent(data);
}

static int sun6i_r_intc_nmi_set_type(struct irq_data *data, unsigned int type)
{
	u32 nmi_src_type;

	switch (type) {
	case IRQ_TYPE_EDGE_RISING:
		nmi_src_type = SUN6I_NMI_SRC_TYPE_EDGE_RISING;
		break;
	case IRQ_TYPE_EDGE_FALLING:
		nmi_src_type = SUN6I_NMI_SRC_TYPE_EDGE_FALLING;
		break;
	case IRQ_TYPE_LEVEL_HIGH:
		nmi_src_type = SUN6I_NMI_SRC_TYPE_LEVEL_HIGH;
		break;
	case IRQ_TYPE_LEVEL_LOW:
		nmi_src_type = SUN6I_NMI_SRC_TYPE_LEVEL_LOW;
		break;
	default:
		return -EINVAL;
	}

	writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);

	/*
	 * The "External NMI" GIC input connects to a latch inside R_INTC, not
	 * directly to the pin. So the GIC trigger type does not depend on the
	 * NMI pin trigger type.
	 */
	return irq_chip_set_type_parent(data, IRQ_TYPE_LEVEL_HIGH);
}

static int sun6i_r_intc_nmi_set_irqchip_state(struct irq_data *data,
					      enum irqchip_irq_state which,
					      bool state)
{
	if (which == IRQCHIP_STATE_PENDING && !state)
		sun6i_r_intc_ack_nmi();

	return irq_chip_set_parent_state(data, which, state);
}

static int sun6i_r_intc_irq_set_wake(struct irq_data *data, unsigned int on)
{
	unsigned long offset_from_nmi = data->hwirq - nmi_hwirq;

Annotation

Implementation Notes