drivers/clocksource/timer-ti-dm-systimer.c

Source file repositories/reference/linux-study-clean/drivers/clocksource/timer-ti-dm-systimer.c

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/timer-ti-dm-systimer.c
Extension
.c
Size
22177 bytes
Lines
853
Domain
Driver Families
Bucket
drivers/clocksource
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

subsys_initcall(dmtimer_percpu_timer_startup);

static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa)
{
	struct device_node *arm_timer __free(device_node) =
		of_find_compatible_node(NULL, NULL, "arm,armv7-timer");

	if (of_device_is_available(arm_timer)) {
		pr_warn_once("ARM architected timer wrap issue i940 detected\n");
		return 0;
	}

	if (pa == 0x4882c000)           /* dra7 dmtimer15 */
		return dmtimer_percpu_timer_init(np, 0);
	else if (pa == 0x4882e000)      /* dra7 dmtimer16 */
		return dmtimer_percpu_timer_init(np, 1);

	return 0;
}

/* Clocksource */
static struct dmtimer_clocksource *
to_dmtimer_clocksource(struct clocksource *cs)
{
	return container_of(cs, struct dmtimer_clocksource, dev);
}

static u64 dmtimer_clocksource_read_cycles(struct clocksource *cs)
{
	struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
	struct dmtimer_systimer *t = &clksrc->t;

	return (u64)readl_relaxed(t->base + t->counter);
}

static void __iomem *dmtimer_sched_clock_counter;

static u64 notrace dmtimer_read_sched_clock(void)
{
	return readl_relaxed(dmtimer_sched_clock_counter);
}

static void dmtimer_clocksource_suspend(struct clocksource *cs)
{
	struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
	struct dmtimer_systimer *t = &clksrc->t;

	clksrc->loadval = readl_relaxed(t->base + t->counter);
	dmtimer_systimer_disable(t);
	clk_disable(t->fck);
}

static void dmtimer_clocksource_resume(struct clocksource *cs)
{
	struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
	struct dmtimer_systimer *t = &clksrc->t;
	int error;

	error = clk_enable(t->fck);
	if (error)
		pr_err("could not enable timer fck on resume: %i\n", error);

	dmtimer_systimer_enable(t);
	writel_relaxed(clksrc->loadval, t->base + t->counter);
	writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR,
		       t->base + t->ctrl);
}

static int __init dmtimer_clocksource_init(struct device_node *np)
{
	struct dmtimer_clocksource *clksrc;
	struct dmtimer_systimer *t;
	struct clocksource *dev;
	int error;

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

	dev = &clksrc->dev;
	t = &clksrc->t;

	error = dmtimer_systimer_setup(np, t);
	if (error)
		goto err_out_free;

	dev->name = "dmtimer";
	dev->rating = 300;
	dev->read = dmtimer_clocksource_read_cycles;
	dev->mask = CLOCKSOURCE_MASK(32);

Annotation

Implementation Notes