drivers/clocksource/timer-gxp.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/timer-gxp.c
Extension
.c
Size
5184 bytes
Lines
216
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 gxp_timer {
	void __iomem *counter;
	void __iomem *control;
	struct clock_event_device evt;
};

static struct gxp_timer *gxp_timer;

static void __iomem *system_clock __ro_after_init;

static inline struct gxp_timer *to_gxp_timer(struct clock_event_device *evt_dev)
{
	return container_of(evt_dev, struct gxp_timer, evt);
}

static u64 notrace gxp_sched_read(void)
{
	return readl_relaxed(system_clock);
}

static int gxp_time_set_next_event(unsigned long event, struct clock_event_device *evt_dev)
{
	struct gxp_timer *timer = to_gxp_timer(evt_dev);

	/* Stop counting and disable interrupt before updating */
	writeb_relaxed(MASK_TCS_TC, timer->control);
	writel_relaxed(event, timer->counter);
	writeb_relaxed(MASK_TCS_TC | MASK_TCS_ENABLE, timer->control);

	return 0;
}

static irqreturn_t gxp_timer_interrupt(int irq, void *dev_id)
{
	struct gxp_timer *timer = (struct gxp_timer *)dev_id;

	if (!(readb_relaxed(timer->control) & MASK_TCS_TC))
		return IRQ_NONE;

	writeb_relaxed(MASK_TCS_TC, timer->control);

	timer->evt.event_handler(&timer->evt);

	return IRQ_HANDLED;
}

static int __init gxp_timer_init(struct device_node *node)
{
	void __iomem *base;
	struct clk *clk;
	u32 freq;
	int ret, irq;

	gxp_timer = kzalloc_obj(*gxp_timer);
	if (!gxp_timer) {
		ret = -ENOMEM;
		pr_err("Can't allocate gxp_timer");
		return ret;
	}

	clk = of_clk_get(node, 0);
	if (IS_ERR(clk)) {
		ret = PTR_ERR(clk);
		pr_err("%pOFn clock not found: %d\n", node, ret);
		goto err_free;
	}

	ret = clk_prepare_enable(clk);
	if (ret) {
		pr_err("%pOFn clock enable failed: %d\n", node, ret);
		goto err_clk_enable;
	}

	base = of_iomap(node, 0);
	if (!base) {
		ret = -ENXIO;
		pr_err("Can't map timer base registers");
		goto err_iomap;
	}

	/* Set the offsets to the clock register and timer registers */
	gxp_timer->counter = base + GXP_TIMER_CNT_OFS;
	gxp_timer->control = base + GXP_TIMER_CTRL_OFS;
	system_clock = base + GXP_TIMESTAMP_OFS;

	gxp_timer->evt.name = node->name;
	gxp_timer->evt.rating = 300;
	gxp_timer->evt.features = CLOCK_EVT_FEAT_ONESHOT;
	gxp_timer->evt.set_next_event = gxp_time_set_next_event;
	gxp_timer->evt.cpumask = cpumask_of(0);

Annotation

Implementation Notes