drivers/clocksource/timer-lpc32xx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/timer-lpc32xx.c
Extension
.c
Size
8161 bytes
Lines
311
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 lpc32xx_clock_event_ddata {
	struct clock_event_device evtdev;
	void __iomem *base;
	u32 ticks_per_jiffy;
};

/* Needed for the sched clock */
static void __iomem *clocksource_timer_counter;

static u64 notrace lpc32xx_read_sched_clock(void)
{
	return readl(clocksource_timer_counter);
}

static unsigned long lpc32xx_delay_timer_read(void)
{
	return readl(clocksource_timer_counter);
}

static struct delay_timer lpc32xx_delay_timer = {
	.read_current_timer = lpc32xx_delay_timer_read,
};

static int lpc32xx_clkevt_next_event(unsigned long delta,
				     struct clock_event_device *evtdev)
{
	struct lpc32xx_clock_event_ddata *ddata =
		container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);

	/*
	 * Place timer in reset and program the delta in the match
	 * channel 0 (MR0). When the timer counter matches the value
	 * in MR0 register the match will trigger an interrupt.
	 * After setup the timer is released from reset and enabled.
	 */
	writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
	writel_relaxed(delta, ddata->base + LPC32XX_TIMER_MR0);
	writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);

	return 0;
}

static int lpc32xx_clkevt_shutdown(struct clock_event_device *evtdev)
{
	struct lpc32xx_clock_event_ddata *ddata =
		container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);

	/* Disable the timer */
	writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR);

	return 0;
}

static int lpc32xx_clkevt_oneshot(struct clock_event_device *evtdev)
{
	struct lpc32xx_clock_event_ddata *ddata =
		container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);

	/*
	 * When using oneshot, we must also disable the timer
	 * to wait for the first call to set_next_event().
	 */
	writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR);

	/* Enable interrupt, reset on match and stop on match (MCR). */
	writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
		       LPC32XX_TIMER_MCR_MR0S, ddata->base + LPC32XX_TIMER_MCR);
	return 0;
}

static int lpc32xx_clkevt_periodic(struct clock_event_device *evtdev)
{
	struct lpc32xx_clock_event_ddata *ddata =
		container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);

	/* Enable interrupt and reset on match. */
	writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R,
		       ddata->base + LPC32XX_TIMER_MCR);

	/*
	 * Place timer in reset and program the delta in the match
	 * channel 0 (MR0).
	 */
	writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
	writel_relaxed(ddata->ticks_per_jiffy, ddata->base + LPC32XX_TIMER_MR0);
	writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);

	return 0;
}

Annotation

Implementation Notes