drivers/clocksource/dw_apb_timer.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/dw_apb_timer.c
Extension
.c
Size
11012 bytes
Lines
378
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

// SPDX-License-Identifier: GPL-2.0-only
/*
 * (C) Copyright 2009 Intel Corporation
 * Author: Jacob Pan (jacob.jun.pan@intel.com)
 *
 * Shared with ARM platforms, Jamie Iles, Picochip 2011
 *
 * Support for the Synopsys DesignWare APB Timers.
 */
#include <linux/dw_apb_timer.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/slab.h>

#define APBT_MIN_PERIOD			4
#define APBT_MIN_DELTA_USEC		200

#define APBTMR_N_LOAD_COUNT		0x00
#define APBTMR_N_CURRENT_VALUE		0x04
#define APBTMR_N_CONTROL		0x08
#define APBTMR_N_EOI			0x0c
#define APBTMR_N_INT_STATUS		0x10

#define APBTMRS_INT_STATUS		0xa0
#define APBTMRS_EOI			0xa4
#define APBTMRS_RAW_INT_STATUS		0xa8
#define APBTMRS_COMP_VERSION		0xac

#define APBTMR_CONTROL_ENABLE		(1 << 0)
/* 1: periodic, 0:free running. */
#define APBTMR_CONTROL_MODE_PERIODIC	(1 << 1)
#define APBTMR_CONTROL_INT		(1 << 2)

static inline struct dw_apb_clock_event_device *
ced_to_dw_apb_ced(struct clock_event_device *evt)
{
	return container_of(evt, struct dw_apb_clock_event_device, ced);
}

static inline struct dw_apb_clocksource *
clocksource_to_dw_apb_clocksource(struct clocksource *cs)
{
	return container_of(cs, struct dw_apb_clocksource, cs);
}

static inline u32 apbt_readl(struct dw_apb_timer *timer, unsigned long offs)
{
	return readl(timer->base + offs);
}

static inline void apbt_writel(struct dw_apb_timer *timer, u32 val,
			unsigned long offs)
{
	writel(val, timer->base + offs);
}

static inline u32 apbt_readl_relaxed(struct dw_apb_timer *timer, unsigned long offs)
{
	return readl_relaxed(timer->base + offs);
}

static inline void apbt_writel_relaxed(struct dw_apb_timer *timer, u32 val,
			unsigned long offs)
{
	writel_relaxed(val, timer->base + offs);
}

static void apbt_eoi(struct dw_apb_timer *timer)
{
	apbt_readl_relaxed(timer, APBTMR_N_EOI);
}

static irqreturn_t dw_apb_clockevent_irq(int irq, void *data)
{
	struct clock_event_device *evt = data;
	struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);

	if (!evt->event_handler) {
		pr_info("Spurious APBT timer interrupt %d\n", irq);
		return IRQ_NONE;
	}

	if (dw_ced->eoi)
		dw_ced->eoi(&dw_ced->timer);

	evt->event_handler(evt);
	return IRQ_HANDLED;

Annotation

Implementation Notes