162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2011
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson
662306a36Sopenharmony_ci * Author: Sundar Iyer for ST-Ericsson
762306a36Sopenharmony_ci * sched_clock implementation is based on:
862306a36Sopenharmony_ci * plat-nomadik/timer.c Linus Walleij <linus.walleij@stericsson.com>
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * DBx500-PRCMU Timer
1162306a36Sopenharmony_ci * The PRCMU has 5 timers which are available in a always-on
1262306a36Sopenharmony_ci * power domain.  We use the Timer 4 for our always-on clock
1362306a36Sopenharmony_ci * source on DB8500.
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/of_address.h>
1762306a36Sopenharmony_ci#include <linux/clockchips.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define RATE_32K		32768
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define TIMER_MODE_CONTINUOUS	0x1
2262306a36Sopenharmony_ci#define TIMER_DOWNCOUNT_VAL	0xffffffff
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define PRCMU_TIMER_REF		0
2562306a36Sopenharmony_ci#define PRCMU_TIMER_DOWNCOUNT	0x4
2662306a36Sopenharmony_ci#define PRCMU_TIMER_MODE	0x8
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic void __iomem *clksrc_dbx500_timer_base;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic u64 notrace clksrc_dbx500_prcmu_read(struct clocksource *cs)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	void __iomem *base = clksrc_dbx500_timer_base;
3362306a36Sopenharmony_ci	u32 count, count2;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	do {
3662306a36Sopenharmony_ci		count = readl_relaxed(base + PRCMU_TIMER_DOWNCOUNT);
3762306a36Sopenharmony_ci		count2 = readl_relaxed(base + PRCMU_TIMER_DOWNCOUNT);
3862306a36Sopenharmony_ci	} while (count2 != count);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	/* Negate because the timer is a decrementing counter */
4162306a36Sopenharmony_ci	return ~count;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic struct clocksource clocksource_dbx500_prcmu = {
4562306a36Sopenharmony_ci	.name		= "dbx500-prcmu-timer",
4662306a36Sopenharmony_ci	.rating		= 100,
4762306a36Sopenharmony_ci	.read		= clksrc_dbx500_prcmu_read,
4862306a36Sopenharmony_ci	.mask		= CLOCKSOURCE_MASK(32),
4962306a36Sopenharmony_ci	.flags		= CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic int __init clksrc_dbx500_prcmu_init(struct device_node *node)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	clksrc_dbx500_timer_base = of_iomap(node, 0);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/*
5762306a36Sopenharmony_ci	 * The A9 sub system expects the timer to be configured as
5862306a36Sopenharmony_ci	 * a continuous looping timer.
5962306a36Sopenharmony_ci	 * The PRCMU should configure it but if it for some reason
6062306a36Sopenharmony_ci	 * don't we do it here.
6162306a36Sopenharmony_ci	 */
6262306a36Sopenharmony_ci	if (readl(clksrc_dbx500_timer_base + PRCMU_TIMER_MODE) !=
6362306a36Sopenharmony_ci	    TIMER_MODE_CONTINUOUS) {
6462306a36Sopenharmony_ci		writel(TIMER_MODE_CONTINUOUS,
6562306a36Sopenharmony_ci		       clksrc_dbx500_timer_base + PRCMU_TIMER_MODE);
6662306a36Sopenharmony_ci		writel(TIMER_DOWNCOUNT_VAL,
6762306a36Sopenharmony_ci		       clksrc_dbx500_timer_base + PRCMU_TIMER_REF);
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci	return clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ciTIMER_OF_DECLARE(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4",
7262306a36Sopenharmony_ci		       clksrc_dbx500_prcmu_init);
73