18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/arch/arm/mach-at91/at91rm9200_time.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2003 SAN People
68c2ecf20Sopenharmony_ci *  Copyright (C) 2003 ATMEL
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci#include <linux/irq.h>
128c2ecf20Sopenharmony_ci#include <linux/clk.h>
138c2ecf20Sopenharmony_ci#include <linux/clockchips.h>
148c2ecf20Sopenharmony_ci#include <linux/export.h>
158c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
168c2ecf20Sopenharmony_ci#include <linux/mfd/syscon/atmel-st.h>
178c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
188c2ecf20Sopenharmony_ci#include <linux/regmap.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic unsigned long last_crtr;
218c2ecf20Sopenharmony_cistatic u32 irqmask;
228c2ecf20Sopenharmony_cistatic struct clock_event_device clkevt;
238c2ecf20Sopenharmony_cistatic struct regmap *regmap_st;
248c2ecf20Sopenharmony_cistatic int timer_latch;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * The ST_CRTR is updated asynchronously to the master clock ... but
288c2ecf20Sopenharmony_ci * the updates as seen by the CPU don't seem to be strictly monotonic.
298c2ecf20Sopenharmony_ci * Waiting until we read the same value twice avoids glitching.
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_cistatic inline unsigned long read_CRTR(void)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	unsigned int x1, x2;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	regmap_read(regmap_st, AT91_ST_CRTR, &x1);
368c2ecf20Sopenharmony_ci	do {
378c2ecf20Sopenharmony_ci		regmap_read(regmap_st, AT91_ST_CRTR, &x2);
388c2ecf20Sopenharmony_ci		if (x1 == x2)
398c2ecf20Sopenharmony_ci			break;
408c2ecf20Sopenharmony_ci		x1 = x2;
418c2ecf20Sopenharmony_ci	} while (1);
428c2ecf20Sopenharmony_ci	return x1;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/*
468c2ecf20Sopenharmony_ci * IRQ handler for the timer.
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_cistatic irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	u32 sr;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	regmap_read(regmap_st, AT91_ST_SR, &sr);
538c2ecf20Sopenharmony_ci	sr &= irqmask;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	/*
568c2ecf20Sopenharmony_ci	 * irqs should be disabled here, but as the irq is shared they are only
578c2ecf20Sopenharmony_ci	 * guaranteed to be off if the timer irq is registered first.
588c2ecf20Sopenharmony_ci	 */
598c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!irqs_disabled());
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	/* simulate "oneshot" timer with alarm */
628c2ecf20Sopenharmony_ci	if (sr & AT91_ST_ALMS) {
638c2ecf20Sopenharmony_ci		clkevt.event_handler(&clkevt);
648c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/* periodic mode should handle delayed ticks */
688c2ecf20Sopenharmony_ci	if (sr & AT91_ST_PITS) {
698c2ecf20Sopenharmony_ci		u32	crtr = read_CRTR();
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci		while (((crtr - last_crtr) & AT91_ST_CRTV) >= timer_latch) {
728c2ecf20Sopenharmony_ci			last_crtr += timer_latch;
738c2ecf20Sopenharmony_ci			clkevt.event_handler(&clkevt);
748c2ecf20Sopenharmony_ci		}
758c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/* this irq is shared ... */
798c2ecf20Sopenharmony_ci	return IRQ_NONE;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic u64 read_clk32k(struct clocksource *cs)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	return read_CRTR();
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic struct clocksource clk32k = {
888c2ecf20Sopenharmony_ci	.name		= "32k_counter",
898c2ecf20Sopenharmony_ci	.rating		= 150,
908c2ecf20Sopenharmony_ci	.read		= read_clk32k,
918c2ecf20Sopenharmony_ci	.mask		= CLOCKSOURCE_MASK(20),
928c2ecf20Sopenharmony_ci	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic void clkdev32k_disable_and_flush_irq(void)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	unsigned int val;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/* Disable and flush pending timer interrupts */
1008c2ecf20Sopenharmony_ci	regmap_write(regmap_st, AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS);
1018c2ecf20Sopenharmony_ci	regmap_read(regmap_st, AT91_ST_SR, &val);
1028c2ecf20Sopenharmony_ci	last_crtr = read_CRTR();
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic int clkevt32k_shutdown(struct clock_event_device *evt)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	clkdev32k_disable_and_flush_irq();
1088c2ecf20Sopenharmony_ci	irqmask = 0;
1098c2ecf20Sopenharmony_ci	regmap_write(regmap_st, AT91_ST_IER, irqmask);
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic int clkevt32k_set_oneshot(struct clock_event_device *dev)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	clkdev32k_disable_and_flush_irq();
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/*
1188c2ecf20Sopenharmony_ci	 * ALM for oneshot irqs, set by next_event()
1198c2ecf20Sopenharmony_ci	 * before 32 seconds have passed.
1208c2ecf20Sopenharmony_ci	 */
1218c2ecf20Sopenharmony_ci	irqmask = AT91_ST_ALMS;
1228c2ecf20Sopenharmony_ci	regmap_write(regmap_st, AT91_ST_RTAR, last_crtr);
1238c2ecf20Sopenharmony_ci	regmap_write(regmap_st, AT91_ST_IER, irqmask);
1248c2ecf20Sopenharmony_ci	return 0;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic int clkevt32k_set_periodic(struct clock_event_device *dev)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	clkdev32k_disable_and_flush_irq();
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* PIT for periodic irqs; fixed rate of 1/HZ */
1328c2ecf20Sopenharmony_ci	irqmask = AT91_ST_PITS;
1338c2ecf20Sopenharmony_ci	regmap_write(regmap_st, AT91_ST_PIMR, timer_latch);
1348c2ecf20Sopenharmony_ci	regmap_write(regmap_st, AT91_ST_IER, irqmask);
1358c2ecf20Sopenharmony_ci	return 0;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic int
1398c2ecf20Sopenharmony_ciclkevt32k_next_event(unsigned long delta, struct clock_event_device *dev)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	u32		alm;
1428c2ecf20Sopenharmony_ci	unsigned int	val;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	BUG_ON(delta < 2);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* The alarm IRQ uses absolute time (now+delta), not the relative
1478c2ecf20Sopenharmony_ci	 * time (delta) in our calling convention.  Like all clockevents
1488c2ecf20Sopenharmony_ci	 * using such "match" hardware, we have a race to defend against.
1498c2ecf20Sopenharmony_ci	 *
1508c2ecf20Sopenharmony_ci	 * Our defense here is to have set up the clockevent device so the
1518c2ecf20Sopenharmony_ci	 * delta is at least two.  That way we never end up writing RTAR
1528c2ecf20Sopenharmony_ci	 * with the value then held in CRTR ... which would mean the match
1538c2ecf20Sopenharmony_ci	 * wouldn't trigger until 32 seconds later, after CRTR wraps.
1548c2ecf20Sopenharmony_ci	 */
1558c2ecf20Sopenharmony_ci	alm = read_CRTR();
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* Cancel any pending alarm; flush any pending IRQ */
1588c2ecf20Sopenharmony_ci	regmap_write(regmap_st, AT91_ST_RTAR, alm);
1598c2ecf20Sopenharmony_ci	regmap_read(regmap_st, AT91_ST_SR, &val);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/* Schedule alarm by writing RTAR. */
1628c2ecf20Sopenharmony_ci	alm += delta;
1638c2ecf20Sopenharmony_ci	regmap_write(regmap_st, AT91_ST_RTAR, alm);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	return 0;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic struct clock_event_device clkevt = {
1698c2ecf20Sopenharmony_ci	.name			= "at91_tick",
1708c2ecf20Sopenharmony_ci	.features		= CLOCK_EVT_FEAT_PERIODIC |
1718c2ecf20Sopenharmony_ci				  CLOCK_EVT_FEAT_ONESHOT,
1728c2ecf20Sopenharmony_ci	.rating			= 150,
1738c2ecf20Sopenharmony_ci	.set_next_event		= clkevt32k_next_event,
1748c2ecf20Sopenharmony_ci	.set_state_shutdown	= clkevt32k_shutdown,
1758c2ecf20Sopenharmony_ci	.set_state_periodic	= clkevt32k_set_periodic,
1768c2ecf20Sopenharmony_ci	.set_state_oneshot	= clkevt32k_set_oneshot,
1778c2ecf20Sopenharmony_ci	.tick_resume		= clkevt32k_shutdown,
1788c2ecf20Sopenharmony_ci};
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/*
1818c2ecf20Sopenharmony_ci * ST (system timer) module supports both clockevents and clocksource.
1828c2ecf20Sopenharmony_ci */
1838c2ecf20Sopenharmony_cistatic int __init atmel_st_timer_init(struct device_node *node)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	struct clk *sclk;
1868c2ecf20Sopenharmony_ci	unsigned int sclk_rate, val;
1878c2ecf20Sopenharmony_ci	int irq, ret;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	regmap_st = syscon_node_to_regmap(node);
1908c2ecf20Sopenharmony_ci	if (IS_ERR(regmap_st)) {
1918c2ecf20Sopenharmony_ci		pr_err("Unable to get regmap\n");
1928c2ecf20Sopenharmony_ci		return PTR_ERR(regmap_st);
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/* Disable all timer interrupts, and clear any pending ones */
1968c2ecf20Sopenharmony_ci	regmap_write(regmap_st, AT91_ST_IDR,
1978c2ecf20Sopenharmony_ci		AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
1988c2ecf20Sopenharmony_ci	regmap_read(regmap_st, AT91_ST_SR, &val);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	/* Get the interrupts property */
2018c2ecf20Sopenharmony_ci	irq  = irq_of_parse_and_map(node, 0);
2028c2ecf20Sopenharmony_ci	if (!irq) {
2038c2ecf20Sopenharmony_ci		pr_err("Unable to get IRQ from DT\n");
2048c2ecf20Sopenharmony_ci		return -EINVAL;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* Make IRQs happen for the system timer */
2088c2ecf20Sopenharmony_ci	ret = request_irq(irq, at91rm9200_timer_interrupt,
2098c2ecf20Sopenharmony_ci			  IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
2108c2ecf20Sopenharmony_ci			  "at91_tick", regmap_st);
2118c2ecf20Sopenharmony_ci	if (ret) {
2128c2ecf20Sopenharmony_ci		pr_err("Unable to setup IRQ\n");
2138c2ecf20Sopenharmony_ci		return ret;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	sclk = of_clk_get(node, 0);
2178c2ecf20Sopenharmony_ci	if (IS_ERR(sclk)) {
2188c2ecf20Sopenharmony_ci		pr_err("Unable to get slow clock\n");
2198c2ecf20Sopenharmony_ci		return PTR_ERR(sclk);
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(sclk);
2238c2ecf20Sopenharmony_ci	if (ret) {
2248c2ecf20Sopenharmony_ci		pr_err("Could not enable slow clock\n");
2258c2ecf20Sopenharmony_ci		return ret;
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	sclk_rate = clk_get_rate(sclk);
2298c2ecf20Sopenharmony_ci	if (!sclk_rate) {
2308c2ecf20Sopenharmony_ci		pr_err("Invalid slow clock rate\n");
2318c2ecf20Sopenharmony_ci		return -EINVAL;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci	timer_latch = (sclk_rate + HZ / 2) / HZ;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	/* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used
2368c2ecf20Sopenharmony_ci	 * directly for the clocksource and all clockevents, after adjusting
2378c2ecf20Sopenharmony_ci	 * its prescaler from the 1 Hz default.
2388c2ecf20Sopenharmony_ci	 */
2398c2ecf20Sopenharmony_ci	regmap_write(regmap_st, AT91_ST_RTMR, 1);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/* Setup timer clockevent, with minimum of two ticks (important!!) */
2428c2ecf20Sopenharmony_ci	clkevt.cpumask = cpumask_of(0);
2438c2ecf20Sopenharmony_ci	clockevents_config_and_register(&clkevt, sclk_rate,
2448c2ecf20Sopenharmony_ci					2, AT91_ST_ALMV);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/* register clocksource */
2478c2ecf20Sopenharmony_ci	return clocksource_register_hz(&clk32k, sclk_rate);
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st",
2508c2ecf20Sopenharmony_ci		       atmel_st_timer_init);
251