18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* linux/arch/arm/mach-exynos4/mct.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2011 Samsung Electronics Co., Ltd.
58c2ecf20Sopenharmony_ci *		http://www.samsung.com
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Exynos4 MCT(Multi-Core Timer) support
88c2ecf20Sopenharmony_ci*/
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci#include <linux/irq.h>
128c2ecf20Sopenharmony_ci#include <linux/err.h>
138c2ecf20Sopenharmony_ci#include <linux/clk.h>
148c2ecf20Sopenharmony_ci#include <linux/clockchips.h>
158c2ecf20Sopenharmony_ci#include <linux/cpu.h>
168c2ecf20Sopenharmony_ci#include <linux/delay.h>
178c2ecf20Sopenharmony_ci#include <linux/percpu.h>
188c2ecf20Sopenharmony_ci#include <linux/of.h>
198c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
208c2ecf20Sopenharmony_ci#include <linux/of_address.h>
218c2ecf20Sopenharmony_ci#include <linux/clocksource.h>
228c2ecf20Sopenharmony_ci#include <linux/sched_clock.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define EXYNOS4_MCTREG(x)		(x)
258c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_G_CNT_L		EXYNOS4_MCTREG(0x100)
268c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_G_CNT_U		EXYNOS4_MCTREG(0x104)
278c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_G_CNT_WSTAT		EXYNOS4_MCTREG(0x110)
288c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_G_COMP0_L		EXYNOS4_MCTREG(0x200)
298c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_G_COMP0_U		EXYNOS4_MCTREG(0x204)
308c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_G_COMP0_ADD_INCR	EXYNOS4_MCTREG(0x208)
318c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_G_TCON		EXYNOS4_MCTREG(0x240)
328c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_G_INT_CSTAT		EXYNOS4_MCTREG(0x244)
338c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_G_INT_ENB		EXYNOS4_MCTREG(0x248)
348c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_G_WSTAT		EXYNOS4_MCTREG(0x24C)
358c2ecf20Sopenharmony_ci#define _EXYNOS4_MCT_L_BASE		EXYNOS4_MCTREG(0x300)
368c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_L_BASE(x)		(_EXYNOS4_MCT_L_BASE + (0x100 * x))
378c2ecf20Sopenharmony_ci#define EXYNOS4_MCT_L_MASK		(0xffffff00)
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define MCT_L_TCNTB_OFFSET		(0x00)
408c2ecf20Sopenharmony_ci#define MCT_L_ICNTB_OFFSET		(0x08)
418c2ecf20Sopenharmony_ci#define MCT_L_TCON_OFFSET		(0x20)
428c2ecf20Sopenharmony_ci#define MCT_L_INT_CSTAT_OFFSET		(0x30)
438c2ecf20Sopenharmony_ci#define MCT_L_INT_ENB_OFFSET		(0x34)
448c2ecf20Sopenharmony_ci#define MCT_L_WSTAT_OFFSET		(0x40)
458c2ecf20Sopenharmony_ci#define MCT_G_TCON_START		(1 << 8)
468c2ecf20Sopenharmony_ci#define MCT_G_TCON_COMP0_AUTO_INC	(1 << 1)
478c2ecf20Sopenharmony_ci#define MCT_G_TCON_COMP0_ENABLE		(1 << 0)
488c2ecf20Sopenharmony_ci#define MCT_L_TCON_INTERVAL_MODE	(1 << 2)
498c2ecf20Sopenharmony_ci#define MCT_L_TCON_INT_START		(1 << 1)
508c2ecf20Sopenharmony_ci#define MCT_L_TCON_TIMER_START		(1 << 0)
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define TICK_BASE_CNT	1
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cienum {
558c2ecf20Sopenharmony_ci	MCT_INT_SPI,
568c2ecf20Sopenharmony_ci	MCT_INT_PPI
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cienum {
608c2ecf20Sopenharmony_ci	MCT_G0_IRQ,
618c2ecf20Sopenharmony_ci	MCT_G1_IRQ,
628c2ecf20Sopenharmony_ci	MCT_G2_IRQ,
638c2ecf20Sopenharmony_ci	MCT_G3_IRQ,
648c2ecf20Sopenharmony_ci	MCT_L0_IRQ,
658c2ecf20Sopenharmony_ci	MCT_L1_IRQ,
668c2ecf20Sopenharmony_ci	MCT_L2_IRQ,
678c2ecf20Sopenharmony_ci	MCT_L3_IRQ,
688c2ecf20Sopenharmony_ci	MCT_L4_IRQ,
698c2ecf20Sopenharmony_ci	MCT_L5_IRQ,
708c2ecf20Sopenharmony_ci	MCT_L6_IRQ,
718c2ecf20Sopenharmony_ci	MCT_L7_IRQ,
728c2ecf20Sopenharmony_ci	MCT_NR_IRQS,
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic void __iomem *reg_base;
768c2ecf20Sopenharmony_cistatic unsigned long clk_rate;
778c2ecf20Sopenharmony_cistatic unsigned int mct_int_type;
788c2ecf20Sopenharmony_cistatic int mct_irqs[MCT_NR_IRQS];
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistruct mct_clock_event_device {
818c2ecf20Sopenharmony_ci	struct clock_event_device evt;
828c2ecf20Sopenharmony_ci	unsigned long base;
838c2ecf20Sopenharmony_ci	char name[10];
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic void exynos4_mct_write(unsigned int value, unsigned long offset)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	unsigned long stat_addr;
898c2ecf20Sopenharmony_ci	u32 mask;
908c2ecf20Sopenharmony_ci	u32 i;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	writel_relaxed(value, reg_base + offset);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) {
958c2ecf20Sopenharmony_ci		stat_addr = (offset & EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET;
968c2ecf20Sopenharmony_ci		switch (offset & ~EXYNOS4_MCT_L_MASK) {
978c2ecf20Sopenharmony_ci		case MCT_L_TCON_OFFSET:
988c2ecf20Sopenharmony_ci			mask = 1 << 3;		/* L_TCON write status */
998c2ecf20Sopenharmony_ci			break;
1008c2ecf20Sopenharmony_ci		case MCT_L_ICNTB_OFFSET:
1018c2ecf20Sopenharmony_ci			mask = 1 << 1;		/* L_ICNTB write status */
1028c2ecf20Sopenharmony_ci			break;
1038c2ecf20Sopenharmony_ci		case MCT_L_TCNTB_OFFSET:
1048c2ecf20Sopenharmony_ci			mask = 1 << 0;		/* L_TCNTB write status */
1058c2ecf20Sopenharmony_ci			break;
1068c2ecf20Sopenharmony_ci		default:
1078c2ecf20Sopenharmony_ci			return;
1088c2ecf20Sopenharmony_ci		}
1098c2ecf20Sopenharmony_ci	} else {
1108c2ecf20Sopenharmony_ci		switch (offset) {
1118c2ecf20Sopenharmony_ci		case EXYNOS4_MCT_G_TCON:
1128c2ecf20Sopenharmony_ci			stat_addr = EXYNOS4_MCT_G_WSTAT;
1138c2ecf20Sopenharmony_ci			mask = 1 << 16;		/* G_TCON write status */
1148c2ecf20Sopenharmony_ci			break;
1158c2ecf20Sopenharmony_ci		case EXYNOS4_MCT_G_COMP0_L:
1168c2ecf20Sopenharmony_ci			stat_addr = EXYNOS4_MCT_G_WSTAT;
1178c2ecf20Sopenharmony_ci			mask = 1 << 0;		/* G_COMP0_L write status */
1188c2ecf20Sopenharmony_ci			break;
1198c2ecf20Sopenharmony_ci		case EXYNOS4_MCT_G_COMP0_U:
1208c2ecf20Sopenharmony_ci			stat_addr = EXYNOS4_MCT_G_WSTAT;
1218c2ecf20Sopenharmony_ci			mask = 1 << 1;		/* G_COMP0_U write status */
1228c2ecf20Sopenharmony_ci			break;
1238c2ecf20Sopenharmony_ci		case EXYNOS4_MCT_G_COMP0_ADD_INCR:
1248c2ecf20Sopenharmony_ci			stat_addr = EXYNOS4_MCT_G_WSTAT;
1258c2ecf20Sopenharmony_ci			mask = 1 << 2;		/* G_COMP0_ADD_INCR w status */
1268c2ecf20Sopenharmony_ci			break;
1278c2ecf20Sopenharmony_ci		case EXYNOS4_MCT_G_CNT_L:
1288c2ecf20Sopenharmony_ci			stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
1298c2ecf20Sopenharmony_ci			mask = 1 << 0;		/* G_CNT_L write status */
1308c2ecf20Sopenharmony_ci			break;
1318c2ecf20Sopenharmony_ci		case EXYNOS4_MCT_G_CNT_U:
1328c2ecf20Sopenharmony_ci			stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
1338c2ecf20Sopenharmony_ci			mask = 1 << 1;		/* G_CNT_U write status */
1348c2ecf20Sopenharmony_ci			break;
1358c2ecf20Sopenharmony_ci		default:
1368c2ecf20Sopenharmony_ci			return;
1378c2ecf20Sopenharmony_ci		}
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	/* Wait maximum 1 ms until written values are applied */
1418c2ecf20Sopenharmony_ci	for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++)
1428c2ecf20Sopenharmony_ci		if (readl_relaxed(reg_base + stat_addr) & mask) {
1438c2ecf20Sopenharmony_ci			writel_relaxed(mask, reg_base + stat_addr);
1448c2ecf20Sopenharmony_ci			return;
1458c2ecf20Sopenharmony_ci		}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	panic("MCT hangs after writing %d (offset:0x%lx)\n", value, offset);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* Clocksource handling */
1518c2ecf20Sopenharmony_cistatic void exynos4_mct_frc_start(void)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	u32 reg;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	reg = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON);
1568c2ecf20Sopenharmony_ci	reg |= MCT_G_TCON_START;
1578c2ecf20Sopenharmony_ci	exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/**
1618c2ecf20Sopenharmony_ci * exynos4_read_count_64 - Read all 64-bits of the global counter
1628c2ecf20Sopenharmony_ci *
1638c2ecf20Sopenharmony_ci * This will read all 64-bits of the global counter taking care to make sure
1648c2ecf20Sopenharmony_ci * that the upper and lower half match.  Note that reading the MCT can be quite
1658c2ecf20Sopenharmony_ci * slow (hundreds of nanoseconds) so you should use the 32-bit (lower half
1668c2ecf20Sopenharmony_ci * only) version when possible.
1678c2ecf20Sopenharmony_ci *
1688c2ecf20Sopenharmony_ci * Returns the number of cycles in the global counter.
1698c2ecf20Sopenharmony_ci */
1708c2ecf20Sopenharmony_cistatic u64 exynos4_read_count_64(void)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	unsigned int lo, hi;
1738c2ecf20Sopenharmony_ci	u32 hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	do {
1768c2ecf20Sopenharmony_ci		hi = hi2;
1778c2ecf20Sopenharmony_ci		lo = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L);
1788c2ecf20Sopenharmony_ci		hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U);
1798c2ecf20Sopenharmony_ci	} while (hi != hi2);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	return ((u64)hi << 32) | lo;
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci/**
1858c2ecf20Sopenharmony_ci * exynos4_read_count_32 - Read the lower 32-bits of the global counter
1868c2ecf20Sopenharmony_ci *
1878c2ecf20Sopenharmony_ci * This will read just the lower 32-bits of the global counter.  This is marked
1888c2ecf20Sopenharmony_ci * as notrace so it can be used by the scheduler clock.
1898c2ecf20Sopenharmony_ci *
1908c2ecf20Sopenharmony_ci * Returns the number of cycles in the global counter (lower 32 bits).
1918c2ecf20Sopenharmony_ci */
1928c2ecf20Sopenharmony_cistatic u32 notrace exynos4_read_count_32(void)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	return readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L);
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic u64 exynos4_frc_read(struct clocksource *cs)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	return exynos4_read_count_32();
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic void exynos4_frc_resume(struct clocksource *cs)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	exynos4_mct_frc_start();
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic struct clocksource mct_frc = {
2088c2ecf20Sopenharmony_ci	.name		= "mct-frc",
2098c2ecf20Sopenharmony_ci	.rating		= 450,	/* use value higher than ARM arch timer */
2108c2ecf20Sopenharmony_ci	.read		= exynos4_frc_read,
2118c2ecf20Sopenharmony_ci	.mask		= CLOCKSOURCE_MASK(32),
2128c2ecf20Sopenharmony_ci	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
2138c2ecf20Sopenharmony_ci	.resume		= exynos4_frc_resume,
2148c2ecf20Sopenharmony_ci};
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic u64 notrace exynos4_read_sched_clock(void)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	return exynos4_read_count_32();
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci#if defined(CONFIG_ARM)
2228c2ecf20Sopenharmony_cistatic struct delay_timer exynos4_delay_timer;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic cycles_t exynos4_read_current_timer(void)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	BUILD_BUG_ON_MSG(sizeof(cycles_t) != sizeof(u32),
2278c2ecf20Sopenharmony_ci			 "cycles_t needs to move to 32-bit for ARM64 usage");
2288c2ecf20Sopenharmony_ci	return exynos4_read_count_32();
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci#endif
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic int __init exynos4_clocksource_init(void)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	exynos4_mct_frc_start();
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci#if defined(CONFIG_ARM)
2378c2ecf20Sopenharmony_ci	exynos4_delay_timer.read_current_timer = &exynos4_read_current_timer;
2388c2ecf20Sopenharmony_ci	exynos4_delay_timer.freq = clk_rate;
2398c2ecf20Sopenharmony_ci	register_current_timer_delay(&exynos4_delay_timer);
2408c2ecf20Sopenharmony_ci#endif
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (clocksource_register_hz(&mct_frc, clk_rate))
2438c2ecf20Sopenharmony_ci		panic("%s: can't register clocksource\n", mct_frc.name);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	sched_clock_register(exynos4_read_sched_clock, 32, clk_rate);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return 0;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic void exynos4_mct_comp0_stop(void)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	unsigned int tcon;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON);
2558c2ecf20Sopenharmony_ci	tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON);
2588c2ecf20Sopenharmony_ci	exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic void exynos4_mct_comp0_start(bool periodic, unsigned long cycles)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	unsigned int tcon;
2648c2ecf20Sopenharmony_ci	u64 comp_cycle;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (periodic) {
2698c2ecf20Sopenharmony_ci		tcon |= MCT_G_TCON_COMP0_AUTO_INC;
2708c2ecf20Sopenharmony_ci		exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR);
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	comp_cycle = exynos4_read_count_64() + cycles;
2748c2ecf20Sopenharmony_ci	exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L);
2758c2ecf20Sopenharmony_ci	exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_ENB);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	tcon |= MCT_G_TCON_COMP0_ENABLE;
2808c2ecf20Sopenharmony_ci	exynos4_mct_write(tcon , EXYNOS4_MCT_G_TCON);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic int exynos4_comp_set_next_event(unsigned long cycles,
2848c2ecf20Sopenharmony_ci				       struct clock_event_device *evt)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	exynos4_mct_comp0_start(false, cycles);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	return 0;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic int mct_set_state_shutdown(struct clock_event_device *evt)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	exynos4_mct_comp0_stop();
2948c2ecf20Sopenharmony_ci	return 0;
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic int mct_set_state_periodic(struct clock_event_device *evt)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	unsigned long cycles_per_jiffy;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult)
3028c2ecf20Sopenharmony_ci			    >> evt->shift);
3038c2ecf20Sopenharmony_ci	exynos4_mct_comp0_stop();
3048c2ecf20Sopenharmony_ci	exynos4_mct_comp0_start(true, cycles_per_jiffy);
3058c2ecf20Sopenharmony_ci	return 0;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic struct clock_event_device mct_comp_device = {
3098c2ecf20Sopenharmony_ci	.name			= "mct-comp",
3108c2ecf20Sopenharmony_ci	.features		= CLOCK_EVT_FEAT_PERIODIC |
3118c2ecf20Sopenharmony_ci				  CLOCK_EVT_FEAT_ONESHOT,
3128c2ecf20Sopenharmony_ci	.rating			= 250,
3138c2ecf20Sopenharmony_ci	.set_next_event		= exynos4_comp_set_next_event,
3148c2ecf20Sopenharmony_ci	.set_state_periodic	= mct_set_state_periodic,
3158c2ecf20Sopenharmony_ci	.set_state_shutdown	= mct_set_state_shutdown,
3168c2ecf20Sopenharmony_ci	.set_state_oneshot	= mct_set_state_shutdown,
3178c2ecf20Sopenharmony_ci	.set_state_oneshot_stopped = mct_set_state_shutdown,
3188c2ecf20Sopenharmony_ci	.tick_resume		= mct_set_state_shutdown,
3198c2ecf20Sopenharmony_ci};
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct clock_event_device *evt = dev_id;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_CSTAT);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	evt->event_handler(evt);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int exynos4_clockevent_init(void)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	mct_comp_device.cpumask = cpumask_of(0);
3358c2ecf20Sopenharmony_ci	clockevents_config_and_register(&mct_comp_device, clk_rate,
3368c2ecf20Sopenharmony_ci					0xf, 0xffffffff);
3378c2ecf20Sopenharmony_ci	if (request_irq(mct_irqs[MCT_G0_IRQ], exynos4_mct_comp_isr,
3388c2ecf20Sopenharmony_ci			IRQF_TIMER | IRQF_IRQPOLL, "mct_comp_irq",
3398c2ecf20Sopenharmony_ci			&mct_comp_device))
3408c2ecf20Sopenharmony_ci		pr_err("%s: request_irq() failed\n", "mct_comp_irq");
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return 0;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci/* Clock event handling */
3488c2ecf20Sopenharmony_cistatic void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	unsigned long tmp;
3518c2ecf20Sopenharmony_ci	unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START;
3528c2ecf20Sopenharmony_ci	unsigned long offset = mevt->base + MCT_L_TCON_OFFSET;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	tmp = readl_relaxed(reg_base + offset);
3558c2ecf20Sopenharmony_ci	if (tmp & mask) {
3568c2ecf20Sopenharmony_ci		tmp &= ~mask;
3578c2ecf20Sopenharmony_ci		exynos4_mct_write(tmp, offset);
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic void exynos4_mct_tick_start(unsigned long cycles,
3628c2ecf20Sopenharmony_ci				   struct mct_clock_event_device *mevt)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	unsigned long tmp;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	exynos4_mct_tick_stop(mevt);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	tmp = (1 << 31) | cycles;	/* MCT_L_UPDATE_ICNTB */
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* update interrupt count buffer */
3718c2ecf20Sopenharmony_ci	exynos4_mct_write(tmp, mevt->base + MCT_L_ICNTB_OFFSET);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* enable MCT tick interrupt */
3748c2ecf20Sopenharmony_ci	exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	tmp = readl_relaxed(reg_base + mevt->base + MCT_L_TCON_OFFSET);
3778c2ecf20Sopenharmony_ci	tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START |
3788c2ecf20Sopenharmony_ci	       MCT_L_TCON_INTERVAL_MODE;
3798c2ecf20Sopenharmony_ci	exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	/* Clear the MCT tick interrupt */
3858c2ecf20Sopenharmony_ci	if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1)
3868c2ecf20Sopenharmony_ci		exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic int exynos4_tick_set_next_event(unsigned long cycles,
3908c2ecf20Sopenharmony_ci				       struct clock_event_device *evt)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct mct_clock_event_device *mevt;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	mevt = container_of(evt, struct mct_clock_event_device, evt);
3958c2ecf20Sopenharmony_ci	exynos4_mct_tick_start(cycles, mevt);
3968c2ecf20Sopenharmony_ci	return 0;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int set_state_shutdown(struct clock_event_device *evt)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	struct mct_clock_event_device *mevt;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	mevt = container_of(evt, struct mct_clock_event_device, evt);
4048c2ecf20Sopenharmony_ci	exynos4_mct_tick_stop(mevt);
4058c2ecf20Sopenharmony_ci	exynos4_mct_tick_clear(mevt);
4068c2ecf20Sopenharmony_ci	return 0;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic int set_state_periodic(struct clock_event_device *evt)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	struct mct_clock_event_device *mevt;
4128c2ecf20Sopenharmony_ci	unsigned long cycles_per_jiffy;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	mevt = container_of(evt, struct mct_clock_event_device, evt);
4158c2ecf20Sopenharmony_ci	cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult)
4168c2ecf20Sopenharmony_ci			    >> evt->shift);
4178c2ecf20Sopenharmony_ci	exynos4_mct_tick_stop(mevt);
4188c2ecf20Sopenharmony_ci	exynos4_mct_tick_start(cycles_per_jiffy, mevt);
4198c2ecf20Sopenharmony_ci	return 0;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct mct_clock_event_device *mevt = dev_id;
4258c2ecf20Sopenharmony_ci	struct clock_event_device *evt = &mevt->evt;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	/*
4288c2ecf20Sopenharmony_ci	 * This is for supporting oneshot mode.
4298c2ecf20Sopenharmony_ci	 * Mct would generate interrupt periodically
4308c2ecf20Sopenharmony_ci	 * without explicit stopping.
4318c2ecf20Sopenharmony_ci	 */
4328c2ecf20Sopenharmony_ci	if (!clockevent_state_periodic(&mevt->evt))
4338c2ecf20Sopenharmony_ci		exynos4_mct_tick_stop(mevt);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	exynos4_mct_tick_clear(mevt);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	evt->event_handler(evt);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic int exynos4_mct_starting_cpu(unsigned int cpu)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	struct mct_clock_event_device *mevt =
4458c2ecf20Sopenharmony_ci		per_cpu_ptr(&percpu_mct_tick, cpu);
4468c2ecf20Sopenharmony_ci	struct clock_event_device *evt = &mevt->evt;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	mevt->base = EXYNOS4_MCT_L_BASE(cpu);
4498c2ecf20Sopenharmony_ci	snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	evt->name = mevt->name;
4528c2ecf20Sopenharmony_ci	evt->cpumask = cpumask_of(cpu);
4538c2ecf20Sopenharmony_ci	evt->set_next_event = exynos4_tick_set_next_event;
4548c2ecf20Sopenharmony_ci	evt->set_state_periodic = set_state_periodic;
4558c2ecf20Sopenharmony_ci	evt->set_state_shutdown = set_state_shutdown;
4568c2ecf20Sopenharmony_ci	evt->set_state_oneshot = set_state_shutdown;
4578c2ecf20Sopenharmony_ci	evt->set_state_oneshot_stopped = set_state_shutdown;
4588c2ecf20Sopenharmony_ci	evt->tick_resume = set_state_shutdown;
4598c2ecf20Sopenharmony_ci	evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
4608c2ecf20Sopenharmony_ci	evt->rating = 500;	/* use value higher than ARM arch timer */
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	if (mct_int_type == MCT_INT_SPI) {
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		if (evt->irq == -1)
4678c2ecf20Sopenharmony_ci			return -EIO;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci		irq_force_affinity(evt->irq, cpumask_of(cpu));
4708c2ecf20Sopenharmony_ci		enable_irq(evt->irq);
4718c2ecf20Sopenharmony_ci	} else {
4728c2ecf20Sopenharmony_ci		enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0);
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci	clockevents_config_and_register(evt, clk_rate / (TICK_BASE_CNT + 1),
4758c2ecf20Sopenharmony_ci					0xf, 0x7fffffff);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	return 0;
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic int exynos4_mct_dying_cpu(unsigned int cpu)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	struct mct_clock_event_device *mevt =
4838c2ecf20Sopenharmony_ci		per_cpu_ptr(&percpu_mct_tick, cpu);
4848c2ecf20Sopenharmony_ci	struct clock_event_device *evt = &mevt->evt;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	evt->set_state_shutdown(evt);
4878c2ecf20Sopenharmony_ci	if (mct_int_type == MCT_INT_SPI) {
4888c2ecf20Sopenharmony_ci		if (evt->irq != -1)
4898c2ecf20Sopenharmony_ci			disable_irq_nosync(evt->irq);
4908c2ecf20Sopenharmony_ci		exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
4918c2ecf20Sopenharmony_ci	} else {
4928c2ecf20Sopenharmony_ci		disable_percpu_irq(mct_irqs[MCT_L0_IRQ]);
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci	return 0;
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic int __init exynos4_timer_resources(struct device_node *np)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	struct clk *mct_clk, *tick_clk;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	reg_base = of_iomap(np, 0);
5028c2ecf20Sopenharmony_ci	if (!reg_base)
5038c2ecf20Sopenharmony_ci		panic("%s: unable to ioremap mct address space\n", __func__);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	tick_clk = of_clk_get_by_name(np, "fin_pll");
5068c2ecf20Sopenharmony_ci	if (IS_ERR(tick_clk))
5078c2ecf20Sopenharmony_ci		panic("%s: unable to determine tick clock rate\n", __func__);
5088c2ecf20Sopenharmony_ci	clk_rate = clk_get_rate(tick_clk);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	mct_clk = of_clk_get_by_name(np, "mct");
5118c2ecf20Sopenharmony_ci	if (IS_ERR(mct_clk))
5128c2ecf20Sopenharmony_ci		panic("%s: unable to retrieve mct clock instance\n", __func__);
5138c2ecf20Sopenharmony_ci	clk_prepare_enable(mct_clk);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	return 0;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic int __init exynos4_timer_interrupts(struct device_node *np,
5198c2ecf20Sopenharmony_ci					   unsigned int int_type)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	int nr_irqs, i, err, cpu;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	mct_int_type = int_type;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	/* This driver uses only one global timer interrupt */
5268c2ecf20Sopenharmony_ci	mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	/*
5298c2ecf20Sopenharmony_ci	 * Find out the number of local irqs specified. The local
5308c2ecf20Sopenharmony_ci	 * timer irqs are specified after the four global timer
5318c2ecf20Sopenharmony_ci	 * irqs are specified.
5328c2ecf20Sopenharmony_ci	 */
5338c2ecf20Sopenharmony_ci	nr_irqs = of_irq_count(np);
5348c2ecf20Sopenharmony_ci	if (nr_irqs > ARRAY_SIZE(mct_irqs)) {
5358c2ecf20Sopenharmony_ci		pr_err("exynos-mct: too many (%d) interrupts configured in DT\n",
5368c2ecf20Sopenharmony_ci			nr_irqs);
5378c2ecf20Sopenharmony_ci		nr_irqs = ARRAY_SIZE(mct_irqs);
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci	for (i = MCT_L0_IRQ; i < nr_irqs; i++)
5408c2ecf20Sopenharmony_ci		mct_irqs[i] = irq_of_parse_and_map(np, i);
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	if (mct_int_type == MCT_INT_PPI) {
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci		err = request_percpu_irq(mct_irqs[MCT_L0_IRQ],
5458c2ecf20Sopenharmony_ci					 exynos4_mct_tick_isr, "MCT",
5468c2ecf20Sopenharmony_ci					 &percpu_mct_tick);
5478c2ecf20Sopenharmony_ci		WARN(err, "MCT: can't request IRQ %d (%d)\n",
5488c2ecf20Sopenharmony_ci		     mct_irqs[MCT_L0_IRQ], err);
5498c2ecf20Sopenharmony_ci	} else {
5508c2ecf20Sopenharmony_ci		for_each_possible_cpu(cpu) {
5518c2ecf20Sopenharmony_ci			int mct_irq;
5528c2ecf20Sopenharmony_ci			struct mct_clock_event_device *pcpu_mevt =
5538c2ecf20Sopenharmony_ci				per_cpu_ptr(&percpu_mct_tick, cpu);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci			pcpu_mevt->evt.irq = -1;
5568c2ecf20Sopenharmony_ci			if (MCT_L0_IRQ + cpu >= ARRAY_SIZE(mct_irqs))
5578c2ecf20Sopenharmony_ci				break;
5588c2ecf20Sopenharmony_ci			mct_irq = mct_irqs[MCT_L0_IRQ + cpu];
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci			irq_set_status_flags(mct_irq, IRQ_NOAUTOEN);
5618c2ecf20Sopenharmony_ci			if (request_irq(mct_irq,
5628c2ecf20Sopenharmony_ci					exynos4_mct_tick_isr,
5638c2ecf20Sopenharmony_ci					IRQF_TIMER | IRQF_NOBALANCING,
5648c2ecf20Sopenharmony_ci					pcpu_mevt->name, pcpu_mevt)) {
5658c2ecf20Sopenharmony_ci				pr_err("exynos-mct: cannot register IRQ (cpu%d)\n",
5668c2ecf20Sopenharmony_ci									cpu);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci				continue;
5698c2ecf20Sopenharmony_ci			}
5708c2ecf20Sopenharmony_ci			pcpu_mevt->evt.irq = mct_irq;
5718c2ecf20Sopenharmony_ci		}
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	/* Install hotplug callbacks which configure the timer on this CPU */
5758c2ecf20Sopenharmony_ci	err = cpuhp_setup_state(CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
5768c2ecf20Sopenharmony_ci				"clockevents/exynos4/mct_timer:starting",
5778c2ecf20Sopenharmony_ci				exynos4_mct_starting_cpu,
5788c2ecf20Sopenharmony_ci				exynos4_mct_dying_cpu);
5798c2ecf20Sopenharmony_ci	if (err)
5808c2ecf20Sopenharmony_ci		goto out_irq;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	return 0;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ciout_irq:
5858c2ecf20Sopenharmony_ci	if (mct_int_type == MCT_INT_PPI) {
5868c2ecf20Sopenharmony_ci		free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick);
5878c2ecf20Sopenharmony_ci	} else {
5888c2ecf20Sopenharmony_ci		for_each_possible_cpu(cpu) {
5898c2ecf20Sopenharmony_ci			struct mct_clock_event_device *pcpu_mevt =
5908c2ecf20Sopenharmony_ci				per_cpu_ptr(&percpu_mct_tick, cpu);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci			if (pcpu_mevt->evt.irq != -1) {
5938c2ecf20Sopenharmony_ci				free_irq(pcpu_mevt->evt.irq, pcpu_mevt);
5948c2ecf20Sopenharmony_ci				pcpu_mevt->evt.irq = -1;
5958c2ecf20Sopenharmony_ci			}
5968c2ecf20Sopenharmony_ci		}
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci	return err;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic int __init mct_init_dt(struct device_node *np, unsigned int int_type)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	int ret;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	ret = exynos4_timer_resources(np);
6068c2ecf20Sopenharmony_ci	if (ret)
6078c2ecf20Sopenharmony_ci		return ret;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	ret = exynos4_timer_interrupts(np, int_type);
6108c2ecf20Sopenharmony_ci	if (ret)
6118c2ecf20Sopenharmony_ci		return ret;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	ret = exynos4_clocksource_init();
6148c2ecf20Sopenharmony_ci	if (ret)
6158c2ecf20Sopenharmony_ci		return ret;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	return exynos4_clockevent_init();
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic int __init mct_init_spi(struct device_node *np)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	return mct_init_dt(np, MCT_INT_SPI);
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cistatic int __init mct_init_ppi(struct device_node *np)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	return mct_init_dt(np, MCT_INT_PPI);
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi);
6318c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi);
632