drivers/clocksource/mxs_timer.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/mxs_timer.c
Extension
.c
Size
7498 bytes
Lines
274
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+
//
//  Copyright (C) 2000-2001 Deep Blue Solutions
//  Copyright (C) 2002 Shane Nay (shane@minirl.com)
//  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
//  Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
//  Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.

#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/clockchips.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/stmp_device.h>
#include <linux/sched_clock.h>

/*
 * There are 2 versions of the timrot on Freescale MXS-based SoCs.
 * The v1 on MX23 only gets 16 bits counter, while v2 on MX28
 * extends the counter to 32 bits.
 *
 * The implementation uses two timers, one for clock_event and
 * another for clocksource. MX28 uses timrot 0 and 1, while MX23
 * uses 0 and 2.
 */

#define MX23_TIMROT_VERSION_OFFSET	0x0a0
#define MX28_TIMROT_VERSION_OFFSET	0x120
#define BP_TIMROT_MAJOR_VERSION		24
#define BV_TIMROT_VERSION_1		0x01
#define BV_TIMROT_VERSION_2		0x02
#define timrot_is_v1()	(timrot_major_version == BV_TIMROT_VERSION_1)

/*
 * There are 4 registers for each timrotv2 instance, and 2 registers
 * for each timrotv1. So address step 0x40 in macros below strides
 * one instance of timrotv2 while two instances of timrotv1.
 *
 * As the result, HW_TIMROT_XXXn(1) defines the address of timrot1
 * on MX28 while timrot2 on MX23.
 */
/* common between v1 and v2 */
#define HW_TIMROT_ROTCTRL		0x00
#define HW_TIMROT_TIMCTRLn(n)		(0x20 + (n) * 0x40)
/* v1 only */
#define HW_TIMROT_TIMCOUNTn(n)		(0x30 + (n) * 0x40)
/* v2 only */
#define HW_TIMROT_RUNNING_COUNTn(n)	(0x30 + (n) * 0x40)
#define HW_TIMROT_FIXED_COUNTn(n)	(0x40 + (n) * 0x40)

#define BM_TIMROT_TIMCTRLn_RELOAD	(1 << 6)
#define BM_TIMROT_TIMCTRLn_UPDATE	(1 << 7)
#define BM_TIMROT_TIMCTRLn_IRQ_EN	(1 << 14)
#define BM_TIMROT_TIMCTRLn_IRQ		(1 << 15)
#define BP_TIMROT_TIMCTRLn_SELECT	0
#define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL		0x8
#define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL		0xb
#define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS	0xf

static struct clock_event_device mxs_clockevent_device;

static void __iomem *mxs_timrot_base;
static u32 timrot_major_version;

static inline void timrot_irq_disable(void)
{
	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
}

static inline void timrot_irq_enable(void)
{
	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_SET);
}

static void timrot_irq_acknowledge(void)
{
	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ, mxs_timrot_base +
		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
}

static u64 timrotv1_get_cycles(struct clocksource *cs)
{
	return ~((__raw_readl(mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1))
			& 0xffff0000) >> 16);
}

Annotation

Implementation Notes