drivers/irqchip/irq-loongson-pch-lpc.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-loongson-pch-lpc.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-loongson-pch-lpc.c
Extension
.c
Size
7138 bytes
Lines
294
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 pch_lpc {
	void __iomem		*base;
	struct irq_domain	*lpc_domain;
	raw_spinlock_t		lpc_lock;
	u32			saved_reg_ctl;
	u32			saved_reg_ena;
	u32			saved_reg_pol;
};

static struct pch_lpc *pch_lpc_priv;
struct fwnode_handle *pch_lpc_handle;

static void lpc_irq_ack(struct irq_data *d)
{
	unsigned long flags;
	struct pch_lpc *priv = d->domain->host_data;

	raw_spin_lock_irqsave(&priv->lpc_lock, flags);
	writel(0x1 << d->hwirq, priv->base + LPC_INT_CLR);
	raw_spin_unlock_irqrestore(&priv->lpc_lock, flags);
}

static void lpc_irq_mask(struct irq_data *d)
{
	unsigned long flags;
	struct pch_lpc *priv = d->domain->host_data;

	raw_spin_lock_irqsave(&priv->lpc_lock, flags);
	writel(readl(priv->base + LPC_INT_ENA) & (~(0x1 << (d->hwirq))),
			priv->base + LPC_INT_ENA);
	raw_spin_unlock_irqrestore(&priv->lpc_lock, flags);
}

static void lpc_irq_unmask(struct irq_data *d)
{
	unsigned long flags;
	struct pch_lpc *priv = d->domain->host_data;

	raw_spin_lock_irqsave(&priv->lpc_lock, flags);
	writel(readl(priv->base + LPC_INT_ENA) | (0x1 << (d->hwirq)),
			priv->base + LPC_INT_ENA);
	raw_spin_unlock_irqrestore(&priv->lpc_lock, flags);
}

static int lpc_irq_set_type(struct irq_data *d, unsigned int type)
{
	u32 val;
	u32 mask = 0x1 << (d->hwirq);
	struct pch_lpc *priv = d->domain->host_data;

	if (!(type & IRQ_TYPE_LEVEL_MASK))
		return 0;

	val = readl(priv->base + LPC_INT_POL);

	if (type == IRQ_TYPE_LEVEL_HIGH)
		val |= mask;
	else
		val &= ~mask;

	writel(val, priv->base + LPC_INT_POL);

	return 0;
}

static const struct irq_chip pch_lpc_irq_chip = {
	.name			= "PCH LPC",
	.irq_mask		= lpc_irq_mask,
	.irq_unmask		= lpc_irq_unmask,
	.irq_ack		= lpc_irq_ack,
	.irq_set_type		= lpc_irq_set_type,
	.flags			= IRQCHIP_SKIP_SET_WAKE,
};

static void lpc_irq_dispatch(struct irq_desc *desc)
{
	u32 pending, bit;
	struct irq_chip *chip = irq_desc_get_chip(desc);
	struct pch_lpc *priv = irq_desc_get_handler_data(desc);

	chained_irq_enter(chip, desc);

	pending = readl(priv->base + LPC_INT_ENA);
	pending &= readl(priv->base + LPC_INT_STS);
	if (!pending)
		spurious_interrupt();

	while (pending) {
		bit = __ffs(pending);

Annotation

Implementation Notes