drivers/irqchip/irq-renesas-rzt2h.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-renesas-rzt2h.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-renesas-rzt2h.c
Extension
.c
Size
16245 bytes
Lines
541
Domain
Driver Families
Bucket
drivers/irqchip
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 rzt2h_icu_priv {
	void __iomem		*base_ns;
	void __iomem		*base_s;
	struct irq_fwspec	fwspec[RZT2H_ICU_NUM_IRQ];
	raw_spinlock_t		lock;
};

void rzt2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
				u16 req_no)
{
	struct rzt2h_icu_priv *priv = platform_get_drvdata(icu_dev);
	u8 y, upper;
	u32 val;

	y = dmac_channel / 3;
	upper = dmac_channel % 3;

	guard(raw_spinlock_irqsave)(&priv->lock);
	val = readl(priv->base_ns + RZT2H_ICU_DMACn_RSSELi(dmac_index, y));
	val &= ~RZT2H_ICU_DMAC_REQ_SELx_MASK(upper);
	val |= RZT2H_ICU_DMAC_REQ_SELx_PREP(upper, req_no);
	writel(val, priv->base_ns + RZT2H_ICU_DMACn_RSSELi(dmac_index, y));
}
EXPORT_SYMBOL_GPL(rzt2h_icu_register_dma_req);

static inline struct rzt2h_icu_priv *irq_data_to_priv(struct irq_data *data)
{
	return data->domain->host_data;
}

static inline int rzt2h_icu_irq_to_offset(struct irq_data *d, void __iomem **base,
					  unsigned int *offset)
{
	struct rzt2h_icu_priv *priv = irq_data_to_priv(d);
	unsigned int hwirq = irqd_to_hwirq(d);

	/*
	 * Safety IRQs and SEI use a separate register space from the non-safety IRQs.
	 * SEI interrupt number follows immediately after the safety IRQs.
	 */
	if (RZT2H_ICU_IRQ_IN_RANGE(hwirq, IRQ_NS)) {
		*offset = hwirq - RZT2H_ICU_IRQ_NS_START;
		*base = priv->base_ns;
	} else if (RZT2H_ICU_IRQ_IN_RANGE(hwirq, IRQ_S) || RZT2H_ICU_IRQ_IN_RANGE(hwirq, SEI)) {
		*offset = hwirq - RZT2H_ICU_IRQ_S_START;
		*base = priv->base_s;
	} else if (RZT2H_ICU_IRQ_IN_RANGE(hwirq, INTCPU_NS)) {
		*offset = hwirq - RZT2H_ICU_INTCPU_NS_START;
		*base = priv->base_ns;
	} else if (RZT2H_ICU_IRQ_IN_RANGE(hwirq, INTCPU_S)) {
		*offset = hwirq - RZT2H_ICU_INTCPU_S_START;
		*base = priv->base_s;
	} else {
		return -EINVAL;
	}
	return 0;
}

static int rzt2h_icu_irq_set_type(struct irq_data *d, unsigned int type)
{
	struct rzt2h_icu_priv *priv = irq_data_to_priv(d);
	unsigned int offset, parent_type;
	void __iomem *base;
	u32 val, md;
	int ret;

	ret = rzt2h_icu_irq_to_offset(d, &base, &offset);
	if (ret)
		return ret;

	switch (type & IRQ_TYPE_SENSE_MASK) {
	case IRQ_TYPE_LEVEL_LOW:
		md = RZT2H_ICU_MD_LOW_LEVEL;
		parent_type = IRQ_TYPE_LEVEL_HIGH;
		break;
	case IRQ_TYPE_EDGE_FALLING:
		md = RZT2H_ICU_MD_FALLING_EDGE;
		parent_type = IRQ_TYPE_EDGE_RISING;
		break;
	case IRQ_TYPE_EDGE_RISING:
		md = RZT2H_ICU_MD_RISING_EDGE;
		parent_type = IRQ_TYPE_EDGE_RISING;
		break;
	case IRQ_TYPE_EDGE_BOTH:
		md = RZT2H_ICU_MD_BOTH_EDGES;
		parent_type = IRQ_TYPE_EDGE_RISING;
		break;
	default:
		return -EINVAL;
	}

Annotation

Implementation Notes