162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/init.h>
362306a36Sopenharmony_ci#include <linux/clocksource.h>
462306a36Sopenharmony_ci#include <linux/clockchips.h>
562306a36Sopenharmony_ci#include <linux/interrupt.h>
662306a36Sopenharmony_ci#include <linux/irq.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/clk.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <linux/ioport.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/of_address.h>
1462306a36Sopenharmony_ci#include <linux/of_irq.h>
1562306a36Sopenharmony_ci#include <linux/sched_clock.h>
1662306a36Sopenharmony_ci#include <linux/syscore_ops.h>
1762306a36Sopenharmony_ci#include <soc/at91/atmel_tcb.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/*
2162306a36Sopenharmony_ci * We're configured to use a specific TC block, one that's not hooked
2262306a36Sopenharmony_ci * up to external hardware, to provide a time solution:
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci *   - Two channels combine to create a free-running 32 bit counter
2562306a36Sopenharmony_ci *     with a base rate of 5+ MHz, packaged as a clocksource (with
2662306a36Sopenharmony_ci *     resolution better than 200 nsec).
2762306a36Sopenharmony_ci *   - Some chips support 32 bit counter. A single channel is used for
2862306a36Sopenharmony_ci *     this 32 bit free-running counter. the second channel is not used.
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci *   - The third channel may be used to provide a clockevent source, used in
3162306a36Sopenharmony_ci *   either periodic or oneshot mode. For 16-bit counter its runs at 32 KiHZ,
3262306a36Sopenharmony_ci *   and can handle delays of up to two seconds. For 32-bit counters, it runs at
3362306a36Sopenharmony_ci *   the same rate as the clocksource
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * REVISIT behavior during system suspend states... we should disable
3662306a36Sopenharmony_ci * all clocks and save the power.  Easily done for clockevent devices,
3762306a36Sopenharmony_ci * but clocksources won't necessarily get the needed notifications.
3862306a36Sopenharmony_ci * For deeper system sleep states, this will be mandatory...
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic void __iomem *tcaddr;
4262306a36Sopenharmony_cistatic struct
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	u32 cmr;
4562306a36Sopenharmony_ci	u32 imr;
4662306a36Sopenharmony_ci	u32 rc;
4762306a36Sopenharmony_ci	bool clken;
4862306a36Sopenharmony_ci} tcb_cache[3];
4962306a36Sopenharmony_cistatic u32 bmr_cache;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic const u8 atmel_tcb_divisors[] = { 2, 8, 32, 128 };
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic u64 tc_get_cycles(struct clocksource *cs)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	unsigned long	flags;
5662306a36Sopenharmony_ci	u32		lower, upper;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	raw_local_irq_save(flags);
5962306a36Sopenharmony_ci	do {
6062306a36Sopenharmony_ci		upper = readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV));
6162306a36Sopenharmony_ci		lower = readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV));
6262306a36Sopenharmony_ci	} while (upper != readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV)));
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	raw_local_irq_restore(flags);
6562306a36Sopenharmony_ci	return (upper << 16) | lower;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic u64 tc_get_cycles32(struct clocksource *cs)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	return readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV));
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic void tc_clksrc_suspend(struct clocksource *cs)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	int i;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tcb_cache); i++) {
7862306a36Sopenharmony_ci		tcb_cache[i].cmr = readl(tcaddr + ATMEL_TC_REG(i, CMR));
7962306a36Sopenharmony_ci		tcb_cache[i].imr = readl(tcaddr + ATMEL_TC_REG(i, IMR));
8062306a36Sopenharmony_ci		tcb_cache[i].rc = readl(tcaddr + ATMEL_TC_REG(i, RC));
8162306a36Sopenharmony_ci		tcb_cache[i].clken = !!(readl(tcaddr + ATMEL_TC_REG(i, SR)) &
8262306a36Sopenharmony_ci					ATMEL_TC_CLKSTA);
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	bmr_cache = readl(tcaddr + ATMEL_TC_BMR);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic void tc_clksrc_resume(struct clocksource *cs)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	int i;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tcb_cache); i++) {
9362306a36Sopenharmony_ci		/* Restore registers for the channel, RA and RB are not used  */
9462306a36Sopenharmony_ci		writel(tcb_cache[i].cmr, tcaddr + ATMEL_TC_REG(i, CMR));
9562306a36Sopenharmony_ci		writel(tcb_cache[i].rc, tcaddr + ATMEL_TC_REG(i, RC));
9662306a36Sopenharmony_ci		writel(0, tcaddr + ATMEL_TC_REG(i, RA));
9762306a36Sopenharmony_ci		writel(0, tcaddr + ATMEL_TC_REG(i, RB));
9862306a36Sopenharmony_ci		/* Disable all the interrupts */
9962306a36Sopenharmony_ci		writel(0xff, tcaddr + ATMEL_TC_REG(i, IDR));
10062306a36Sopenharmony_ci		/* Reenable interrupts that were enabled before suspending */
10162306a36Sopenharmony_ci		writel(tcb_cache[i].imr, tcaddr + ATMEL_TC_REG(i, IER));
10262306a36Sopenharmony_ci		/* Start the clock if it was used */
10362306a36Sopenharmony_ci		if (tcb_cache[i].clken)
10462306a36Sopenharmony_ci			writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(i, CCR));
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* Dual channel, chain channels */
10862306a36Sopenharmony_ci	writel(bmr_cache, tcaddr + ATMEL_TC_BMR);
10962306a36Sopenharmony_ci	/* Finally, trigger all the channels*/
11062306a36Sopenharmony_ci	writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic struct clocksource clksrc = {
11462306a36Sopenharmony_ci	.rating         = 200,
11562306a36Sopenharmony_ci	.read           = tc_get_cycles,
11662306a36Sopenharmony_ci	.mask           = CLOCKSOURCE_MASK(32),
11762306a36Sopenharmony_ci	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
11862306a36Sopenharmony_ci	.suspend	= tc_clksrc_suspend,
11962306a36Sopenharmony_ci	.resume		= tc_clksrc_resume,
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic u64 notrace tc_sched_clock_read(void)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	return tc_get_cycles(&clksrc);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic u64 notrace tc_sched_clock_read32(void)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	return tc_get_cycles32(&clksrc);
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic struct delay_timer tc_delay_timer;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic unsigned long tc_delay_timer_read(void)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	return tc_get_cycles(&clksrc);
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic unsigned long notrace tc_delay_timer_read32(void)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	return tc_get_cycles32(&clksrc);
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#ifdef CONFIG_GENERIC_CLOCKEVENTS
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistruct tc_clkevt_device {
14762306a36Sopenharmony_ci	struct clock_event_device	clkevt;
14862306a36Sopenharmony_ci	struct clk			*clk;
14962306a36Sopenharmony_ci	u32				rate;
15062306a36Sopenharmony_ci	void __iomem			*regs;
15162306a36Sopenharmony_ci};
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	return container_of(clkevt, struct tc_clkevt_device, clkevt);
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic u32 timer_clock;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int tc_shutdown(struct clock_event_device *d)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct tc_clkevt_device *tcd = to_tc_clkevt(d);
16362306a36Sopenharmony_ci	void __iomem		*regs = tcd->regs;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	writel(0xff, regs + ATMEL_TC_REG(2, IDR));
16662306a36Sopenharmony_ci	writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));
16762306a36Sopenharmony_ci	if (!clockevent_state_detached(d))
16862306a36Sopenharmony_ci		clk_disable(tcd->clk);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return 0;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int tc_set_oneshot(struct clock_event_device *d)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	struct tc_clkevt_device *tcd = to_tc_clkevt(d);
17662306a36Sopenharmony_ci	void __iomem		*regs = tcd->regs;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	if (clockevent_state_oneshot(d) || clockevent_state_periodic(d))
17962306a36Sopenharmony_ci		tc_shutdown(d);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	clk_enable(tcd->clk);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* count up to RC, then irq and stop */
18462306a36Sopenharmony_ci	writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE |
18562306a36Sopenharmony_ci		     ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR));
18662306a36Sopenharmony_ci	writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* set_next_event() configures and starts the timer */
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int tc_set_periodic(struct clock_event_device *d)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct tc_clkevt_device *tcd = to_tc_clkevt(d);
19562306a36Sopenharmony_ci	void __iomem		*regs = tcd->regs;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (clockevent_state_oneshot(d) || clockevent_state_periodic(d))
19862306a36Sopenharmony_ci		tc_shutdown(d);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	/* By not making the gentime core emulate periodic mode on top
20162306a36Sopenharmony_ci	 * of oneshot, we get lower overhead and improved accuracy.
20262306a36Sopenharmony_ci	 */
20362306a36Sopenharmony_ci	clk_enable(tcd->clk);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	/* count up to RC, then irq and restart */
20662306a36Sopenharmony_ci	writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
20762306a36Sopenharmony_ci		     regs + ATMEL_TC_REG(2, CMR));
20862306a36Sopenharmony_ci	writel((tcd->rate + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/* Enable clock and interrupts on RC compare */
21162306a36Sopenharmony_ci	writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* go go gadget! */
21462306a36Sopenharmony_ci	writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, regs +
21562306a36Sopenharmony_ci		     ATMEL_TC_REG(2, CCR));
21662306a36Sopenharmony_ci	return 0;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic int tc_next_event(unsigned long delta, struct clock_event_device *d)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	writel_relaxed(delta, tcaddr + ATMEL_TC_REG(2, RC));
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* go go gadget! */
22462306a36Sopenharmony_ci	writel_relaxed(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
22562306a36Sopenharmony_ci			tcaddr + ATMEL_TC_REG(2, CCR));
22662306a36Sopenharmony_ci	return 0;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic struct tc_clkevt_device clkevt = {
23062306a36Sopenharmony_ci	.clkevt	= {
23162306a36Sopenharmony_ci		.features		= CLOCK_EVT_FEAT_PERIODIC |
23262306a36Sopenharmony_ci					  CLOCK_EVT_FEAT_ONESHOT,
23362306a36Sopenharmony_ci		/* Should be lower than at91rm9200's system timer */
23462306a36Sopenharmony_ci		.rating			= 125,
23562306a36Sopenharmony_ci		.set_next_event		= tc_next_event,
23662306a36Sopenharmony_ci		.set_state_shutdown	= tc_shutdown,
23762306a36Sopenharmony_ci		.set_state_periodic	= tc_set_periodic,
23862306a36Sopenharmony_ci		.set_state_oneshot	= tc_set_oneshot,
23962306a36Sopenharmony_ci	},
24062306a36Sopenharmony_ci};
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic irqreturn_t ch2_irq(int irq, void *handle)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct tc_clkevt_device	*dev = handle;
24562306a36Sopenharmony_ci	unsigned int		sr;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	sr = readl_relaxed(dev->regs + ATMEL_TC_REG(2, SR));
24862306a36Sopenharmony_ci	if (sr & ATMEL_TC_CPCS) {
24962306a36Sopenharmony_ci		dev->clkevt.event_handler(&dev->clkevt);
25062306a36Sopenharmony_ci		return IRQ_HANDLED;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	return IRQ_NONE;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	int ret;
25962306a36Sopenharmony_ci	struct clk *t2_clk = tc->clk[2];
26062306a36Sopenharmony_ci	int irq = tc->irq[2];
26162306a36Sopenharmony_ci	int bits = tc->tcb_config->counter_width;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* try to enable t2 clk to avoid future errors in mode change */
26462306a36Sopenharmony_ci	ret = clk_prepare_enable(t2_clk);
26562306a36Sopenharmony_ci	if (ret)
26662306a36Sopenharmony_ci		return ret;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	clkevt.regs = tc->regs;
26962306a36Sopenharmony_ci	clkevt.clk = t2_clk;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (bits == 32) {
27262306a36Sopenharmony_ci		timer_clock = divisor_idx;
27362306a36Sopenharmony_ci		clkevt.rate = clk_get_rate(t2_clk) / atmel_tcb_divisors[divisor_idx];
27462306a36Sopenharmony_ci	} else {
27562306a36Sopenharmony_ci		ret = clk_prepare_enable(tc->slow_clk);
27662306a36Sopenharmony_ci		if (ret) {
27762306a36Sopenharmony_ci			clk_disable_unprepare(t2_clk);
27862306a36Sopenharmony_ci			return ret;
27962306a36Sopenharmony_ci		}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		clkevt.rate = clk_get_rate(tc->slow_clk);
28262306a36Sopenharmony_ci		timer_clock = ATMEL_TC_TIMER_CLOCK5;
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	clk_disable(t2_clk);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	clkevt.clkevt.cpumask = cpumask_of(0);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	ret = request_irq(irq, ch2_irq, IRQF_TIMER, "tc_clkevt", &clkevt);
29062306a36Sopenharmony_ci	if (ret) {
29162306a36Sopenharmony_ci		clk_unprepare(t2_clk);
29262306a36Sopenharmony_ci		if (bits != 32)
29362306a36Sopenharmony_ci			clk_disable_unprepare(tc->slow_clk);
29462306a36Sopenharmony_ci		return ret;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	clockevents_config_and_register(&clkevt.clkevt, clkevt.rate, 1, BIT(bits) - 1);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	return ret;
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci#else /* !CONFIG_GENERIC_CLOCKEVENTS */
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	/* NOTHING */
30762306a36Sopenharmony_ci	return 0;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci#endif
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic void __init tcb_setup_dual_chan(struct atmel_tc *tc, int mck_divisor_idx)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	/* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */
31562306a36Sopenharmony_ci	writel(mck_divisor_idx			/* likely divide-by-8 */
31662306a36Sopenharmony_ci			| ATMEL_TC_WAVE
31762306a36Sopenharmony_ci			| ATMEL_TC_WAVESEL_UP		/* free-run */
31862306a36Sopenharmony_ci			| ATMEL_TC_ASWTRG_SET		/* TIOA0 rises at software trigger */
31962306a36Sopenharmony_ci			| ATMEL_TC_ACPA_SET		/* TIOA0 rises at 0 */
32062306a36Sopenharmony_ci			| ATMEL_TC_ACPC_CLEAR,		/* (duty cycle 50%) */
32162306a36Sopenharmony_ci			tcaddr + ATMEL_TC_REG(0, CMR));
32262306a36Sopenharmony_ci	writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
32362306a36Sopenharmony_ci	writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
32462306a36Sopenharmony_ci	writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));	/* no irqs */
32562306a36Sopenharmony_ci	writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* channel 1:  waveform mode, input TIOA0 */
32862306a36Sopenharmony_ci	writel(ATMEL_TC_XC1			/* input: TIOA0 */
32962306a36Sopenharmony_ci			| ATMEL_TC_WAVE
33062306a36Sopenharmony_ci			| ATMEL_TC_WAVESEL_UP,		/* free-run */
33162306a36Sopenharmony_ci			tcaddr + ATMEL_TC_REG(1, CMR));
33262306a36Sopenharmony_ci	writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR));	/* no irqs */
33362306a36Sopenharmony_ci	writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* chain channel 0 to channel 1*/
33662306a36Sopenharmony_ci	writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
33762306a36Sopenharmony_ci	/* then reset all the timers */
33862306a36Sopenharmony_ci	writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_idx)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	/* channel 0:  waveform mode, input mclk/8 */
34462306a36Sopenharmony_ci	writel(mck_divisor_idx			/* likely divide-by-8 */
34562306a36Sopenharmony_ci			| ATMEL_TC_WAVE
34662306a36Sopenharmony_ci			| ATMEL_TC_WAVESEL_UP,		/* free-run */
34762306a36Sopenharmony_ci			tcaddr + ATMEL_TC_REG(0, CMR));
34862306a36Sopenharmony_ci	writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));	/* no irqs */
34962306a36Sopenharmony_ci	writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* then reset all the timers */
35262306a36Sopenharmony_ci	writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic struct atmel_tcb_config tcb_rm9200_config = {
35662306a36Sopenharmony_ci	.counter_width = 16,
35762306a36Sopenharmony_ci};
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic struct atmel_tcb_config tcb_sam9x5_config = {
36062306a36Sopenharmony_ci	.counter_width = 32,
36162306a36Sopenharmony_ci};
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic struct atmel_tcb_config tcb_sama5d2_config = {
36462306a36Sopenharmony_ci	.counter_width = 32,
36562306a36Sopenharmony_ci	.has_gclk = 1,
36662306a36Sopenharmony_ci};
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic const struct of_device_id atmel_tcb_of_match[] = {
36962306a36Sopenharmony_ci	{ .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, },
37062306a36Sopenharmony_ci	{ .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, },
37162306a36Sopenharmony_ci	{ .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, },
37262306a36Sopenharmony_ci	{ /* sentinel */ }
37362306a36Sopenharmony_ci};
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic int __init tcb_clksrc_init(struct device_node *node)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	struct atmel_tc tc;
37862306a36Sopenharmony_ci	struct clk *t0_clk;
37962306a36Sopenharmony_ci	const struct of_device_id *match;
38062306a36Sopenharmony_ci	u64 (*tc_sched_clock)(void);
38162306a36Sopenharmony_ci	u32 rate, divided_rate = 0;
38262306a36Sopenharmony_ci	int best_divisor_idx = -1;
38362306a36Sopenharmony_ci	int bits;
38462306a36Sopenharmony_ci	int i;
38562306a36Sopenharmony_ci	int ret;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* Protect against multiple calls */
38862306a36Sopenharmony_ci	if (tcaddr)
38962306a36Sopenharmony_ci		return 0;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	tc.regs = of_iomap(node->parent, 0);
39262306a36Sopenharmony_ci	if (!tc.regs)
39362306a36Sopenharmony_ci		return -ENXIO;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	t0_clk = of_clk_get_by_name(node->parent, "t0_clk");
39662306a36Sopenharmony_ci	if (IS_ERR(t0_clk))
39762306a36Sopenharmony_ci		return PTR_ERR(t0_clk);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	tc.slow_clk = of_clk_get_by_name(node->parent, "slow_clk");
40062306a36Sopenharmony_ci	if (IS_ERR(tc.slow_clk))
40162306a36Sopenharmony_ci		return PTR_ERR(tc.slow_clk);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	tc.clk[0] = t0_clk;
40462306a36Sopenharmony_ci	tc.clk[1] = of_clk_get_by_name(node->parent, "t1_clk");
40562306a36Sopenharmony_ci	if (IS_ERR(tc.clk[1]))
40662306a36Sopenharmony_ci		tc.clk[1] = t0_clk;
40762306a36Sopenharmony_ci	tc.clk[2] = of_clk_get_by_name(node->parent, "t2_clk");
40862306a36Sopenharmony_ci	if (IS_ERR(tc.clk[2]))
40962306a36Sopenharmony_ci		tc.clk[2] = t0_clk;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	tc.irq[2] = of_irq_get(node->parent, 2);
41262306a36Sopenharmony_ci	if (tc.irq[2] <= 0) {
41362306a36Sopenharmony_ci		tc.irq[2] = of_irq_get(node->parent, 0);
41462306a36Sopenharmony_ci		if (tc.irq[2] <= 0)
41562306a36Sopenharmony_ci			return -EINVAL;
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	match = of_match_node(atmel_tcb_of_match, node->parent);
41962306a36Sopenharmony_ci	if (!match)
42062306a36Sopenharmony_ci		return -ENODEV;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	tc.tcb_config = match->data;
42362306a36Sopenharmony_ci	bits = tc.tcb_config->counter_width;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tc.irq); i++)
42662306a36Sopenharmony_ci		writel(ATMEL_TC_ALL_IRQ, tc.regs + ATMEL_TC_REG(i, IDR));
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	ret = clk_prepare_enable(t0_clk);
42962306a36Sopenharmony_ci	if (ret) {
43062306a36Sopenharmony_ci		pr_debug("can't enable T0 clk\n");
43162306a36Sopenharmony_ci		return ret;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	/* How fast will we be counting?  Pick something over 5 MHz.  */
43562306a36Sopenharmony_ci	rate = (u32) clk_get_rate(t0_clk);
43662306a36Sopenharmony_ci	i = 0;
43762306a36Sopenharmony_ci	if (tc.tcb_config->has_gclk)
43862306a36Sopenharmony_ci		i = 1;
43962306a36Sopenharmony_ci	for (; i < ARRAY_SIZE(atmel_tcb_divisors); i++) {
44062306a36Sopenharmony_ci		unsigned divisor = atmel_tcb_divisors[i];
44162306a36Sopenharmony_ci		unsigned tmp;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		tmp = rate / divisor;
44462306a36Sopenharmony_ci		pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp);
44562306a36Sopenharmony_ci		if ((best_divisor_idx >= 0) && (tmp < 5 * 1000 * 1000))
44662306a36Sopenharmony_ci			break;
44762306a36Sopenharmony_ci		divided_rate = tmp;
44862306a36Sopenharmony_ci		best_divisor_idx = i;
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	clksrc.name = kbasename(node->parent->full_name);
45262306a36Sopenharmony_ci	clkevt.clkevt.name = kbasename(node->parent->full_name);
45362306a36Sopenharmony_ci	pr_debug("%s at %d.%03d MHz\n", clksrc.name, divided_rate / 1000000,
45462306a36Sopenharmony_ci			((divided_rate % 1000000) + 500) / 1000);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	tcaddr = tc.regs;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	if (bits == 32) {
45962306a36Sopenharmony_ci		/* use appropriate function to read 32 bit counter */
46062306a36Sopenharmony_ci		clksrc.read = tc_get_cycles32;
46162306a36Sopenharmony_ci		/* setup only channel 0 */
46262306a36Sopenharmony_ci		tcb_setup_single_chan(&tc, best_divisor_idx);
46362306a36Sopenharmony_ci		tc_sched_clock = tc_sched_clock_read32;
46462306a36Sopenharmony_ci		tc_delay_timer.read_current_timer = tc_delay_timer_read32;
46562306a36Sopenharmony_ci	} else {
46662306a36Sopenharmony_ci		/* we have three clocks no matter what the
46762306a36Sopenharmony_ci		 * underlying platform supports.
46862306a36Sopenharmony_ci		 */
46962306a36Sopenharmony_ci		ret = clk_prepare_enable(tc.clk[1]);
47062306a36Sopenharmony_ci		if (ret) {
47162306a36Sopenharmony_ci			pr_debug("can't enable T1 clk\n");
47262306a36Sopenharmony_ci			goto err_disable_t0;
47362306a36Sopenharmony_ci		}
47462306a36Sopenharmony_ci		/* setup both channel 0 & 1 */
47562306a36Sopenharmony_ci		tcb_setup_dual_chan(&tc, best_divisor_idx);
47662306a36Sopenharmony_ci		tc_sched_clock = tc_sched_clock_read;
47762306a36Sopenharmony_ci		tc_delay_timer.read_current_timer = tc_delay_timer_read;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	/* and away we go! */
48162306a36Sopenharmony_ci	ret = clocksource_register_hz(&clksrc, divided_rate);
48262306a36Sopenharmony_ci	if (ret)
48362306a36Sopenharmony_ci		goto err_disable_t1;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/* channel 2:  periodic and oneshot timer support */
48662306a36Sopenharmony_ci	ret = setup_clkevents(&tc, best_divisor_idx);
48762306a36Sopenharmony_ci	if (ret)
48862306a36Sopenharmony_ci		goto err_unregister_clksrc;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	sched_clock_register(tc_sched_clock, 32, divided_rate);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	tc_delay_timer.freq = divided_rate;
49362306a36Sopenharmony_ci	register_current_timer_delay(&tc_delay_timer);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	return 0;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cierr_unregister_clksrc:
49862306a36Sopenharmony_ci	clocksource_unregister(&clksrc);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cierr_disable_t1:
50162306a36Sopenharmony_ci	if (bits != 32)
50262306a36Sopenharmony_ci		clk_disable_unprepare(tc.clk[1]);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cierr_disable_t0:
50562306a36Sopenharmony_ci	clk_disable_unprepare(t0_clk);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	tcaddr = NULL;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return ret;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ciTIMER_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-timer", tcb_clksrc_init);
512