drivers/clocksource/timer-imx-sysctr.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/timer-imx-sysctr.c
Extension
.c
Size
4529 bytes
Lines
208
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 sysctr_private {
	u32 cmpcr;
	u32 lo_off;
	u32 hi_off;
};

static void sysctr_timer_enable(struct clock_event_device *evt, bool enable)
{
	struct timer_of *to = to_timer_of(evt);
	struct sysctr_private *priv = to->private_data;
	void __iomem *base = timer_of_base(to);

	writel(enable ? priv->cmpcr | SYS_CTR_EN : priv->cmpcr, base + CMPCR);
}

static void sysctr_irq_acknowledge(struct clock_event_device *evt)
{
	/*
	 * clear the enable bit(EN =0) will clear
	 * the status bit(ISTAT = 0), then the interrupt
	 * signal will be negated(acknowledged).
	 */
	sysctr_timer_enable(evt, false);
}

static inline u64 sysctr_read_counter(struct clock_event_device *evt)
{
	struct timer_of *to = to_timer_of(evt);
	struct sysctr_private *priv = to->private_data;
	void __iomem *base = timer_of_base(to);
	u32 cnt_hi, tmp_hi, cnt_lo;

	do {
		cnt_hi = readl_relaxed(base + priv->hi_off);
		cnt_lo = readl_relaxed(base + priv->lo_off);
		tmp_hi = readl_relaxed(base + priv->hi_off);
	} while (tmp_hi != cnt_hi);

	return  ((u64) cnt_hi << 32) | cnt_lo;
}

static int sysctr_set_next_event(unsigned long delta,
				 struct clock_event_device *evt)
{
	struct timer_of *to = to_timer_of(evt);
	void __iomem *base = timer_of_base(to);
	u32 cmp_hi, cmp_lo;
	u64 next;

	sysctr_timer_enable(evt, false);

	next = sysctr_read_counter(evt);

	next += delta;

	cmp_hi = (next >> 32) & 0x00fffff;
	cmp_lo = next & 0xffffffff;

	writel_relaxed(cmp_hi, base + CMPCV_HI);
	writel_relaxed(cmp_lo, base + CMPCV_LO);

	sysctr_timer_enable(evt, true);

	return 0;
}

static int sysctr_set_state_oneshot(struct clock_event_device *evt)
{
	return 0;
}

static int sysctr_set_state_shutdown(struct clock_event_device *evt)
{
	sysctr_timer_enable(evt, false);

	return 0;
}

static irqreturn_t sysctr_timer_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *evt = dev_id;

	sysctr_irq_acknowledge(evt);

	evt->event_handler(evt);

	return IRQ_HANDLED;
}

static struct timer_of to_sysctr = {

Annotation

Implementation Notes