drivers/clocksource/timer-zevio.c

Source file repositories/reference/linux-study-clean/drivers/clocksource/timer-zevio.c

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/timer-zevio.c
Extension
.c
Size
5570 bytes
Lines
214
Domain
Driver Families
Bucket
drivers/clocksource
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 zevio_timer {
	void __iomem *base;
	void __iomem *timer1, *timer2;
	void __iomem *interrupt_regs;

	struct clk *clk;
	struct clock_event_device clkevt;

	char clocksource_name[64];
	char clockevent_name[64];
};

static int zevio_timer_set_event(unsigned long delta,
				 struct clock_event_device *dev)
{
	struct zevio_timer *timer = container_of(dev, struct zevio_timer,
						 clkevt);

	writel(delta, timer->timer1 + IO_CURRENT_VAL);
	writel(CNTL_RUN_TIMER | CNTL_DEC | CNTL_MATCH(TIMER_MATCH),
			timer->timer1 + IO_CONTROL);

	return 0;
}

static int zevio_timer_shutdown(struct clock_event_device *dev)
{
	struct zevio_timer *timer = container_of(dev, struct zevio_timer,
						 clkevt);

	/* Disable timer interrupts */
	writel(0, timer->interrupt_regs + IO_INTR_MSK);
	writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK);
	/* Stop timer */
	writel(CNTL_STOP_TIMER, timer->timer1 + IO_CONTROL);
	return 0;
}

static int zevio_timer_set_oneshot(struct clock_event_device *dev)
{
	struct zevio_timer *timer = container_of(dev, struct zevio_timer,
						 clkevt);

	/* Enable timer interrupts */
	writel(TIMER_INTR_MSK, timer->interrupt_regs + IO_INTR_MSK);
	writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK);
	return 0;
}

static irqreturn_t zevio_timer_interrupt(int irq, void *dev_id)
{
	struct zevio_timer *timer = dev_id;
	u32 intr;

	intr = readl(timer->interrupt_regs + IO_INTR_ACK);
	if (!(intr & TIMER_INTR_MSK))
		return IRQ_NONE;

	writel(TIMER_INTR_MSK, timer->interrupt_regs + IO_INTR_ACK);
	writel(CNTL_STOP_TIMER, timer->timer1 + IO_CONTROL);

	if (timer->clkevt.event_handler)
		timer->clkevt.event_handler(&timer->clkevt);

	return IRQ_HANDLED;
}

static int __init zevio_timer_add(struct device_node *node)
{
	struct zevio_timer *timer;
	struct resource res;
	int irqnr, ret;

	timer = kzalloc_obj(*timer);
	if (!timer)
		return -ENOMEM;

	timer->base = of_iomap(node, 0);
	if (!timer->base) {
		ret = -EINVAL;
		goto error_free;
	}
	timer->timer1 = timer->base + IO_TIMER1;
	timer->timer2 = timer->base + IO_TIMER2;

	timer->clk = of_clk_get(node, 0);
	if (IS_ERR(timer->clk)) {
		ret = PTR_ERR(timer->clk);
		pr_err("Timer clock not found! (error %d)\n", ret);
		goto error_unmap;

Annotation

Implementation Notes