18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Freescale FlexTimer Module (FTM) timer driver.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2014 Freescale Semiconductor, Inc.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/clk.h>
98c2ecf20Sopenharmony_ci#include <linux/clockchips.h>
108c2ecf20Sopenharmony_ci#include <linux/clocksource.h>
118c2ecf20Sopenharmony_ci#include <linux/err.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci#include <linux/of_address.h>
158c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
168c2ecf20Sopenharmony_ci#include <linux/sched_clock.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <linux/fsl/ftm.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define FTM_SC_CLK(c)	((c) << FTM_SC_CLK_MASK_SHIFT)
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistruct ftm_clock_device {
238c2ecf20Sopenharmony_ci	void __iomem *clksrc_base;
248c2ecf20Sopenharmony_ci	void __iomem *clkevt_base;
258c2ecf20Sopenharmony_ci	unsigned long periodic_cyc;
268c2ecf20Sopenharmony_ci	unsigned long ps;
278c2ecf20Sopenharmony_ci	bool big_endian;
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic struct ftm_clock_device *priv;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic inline u32 ftm_readl(void __iomem *addr)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	if (priv->big_endian)
358c2ecf20Sopenharmony_ci		return ioread32be(addr);
368c2ecf20Sopenharmony_ci	else
378c2ecf20Sopenharmony_ci		return ioread32(addr);
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic inline void ftm_writel(u32 val, void __iomem *addr)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	if (priv->big_endian)
438c2ecf20Sopenharmony_ci		iowrite32be(val, addr);
448c2ecf20Sopenharmony_ci	else
458c2ecf20Sopenharmony_ci		iowrite32(val, addr);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic inline void ftm_counter_enable(void __iomem *base)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	u32 val;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/* select and enable counter clock source */
538c2ecf20Sopenharmony_ci	val = ftm_readl(base + FTM_SC);
548c2ecf20Sopenharmony_ci	val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
558c2ecf20Sopenharmony_ci	val |= priv->ps | FTM_SC_CLK(1);
568c2ecf20Sopenharmony_ci	ftm_writel(val, base + FTM_SC);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic inline void ftm_counter_disable(void __iomem *base)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	u32 val;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* disable counter clock source */
648c2ecf20Sopenharmony_ci	val = ftm_readl(base + FTM_SC);
658c2ecf20Sopenharmony_ci	val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
668c2ecf20Sopenharmony_ci	ftm_writel(val, base + FTM_SC);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic inline void ftm_irq_acknowledge(void __iomem *base)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	u32 val;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	val = ftm_readl(base + FTM_SC);
748c2ecf20Sopenharmony_ci	val &= ~FTM_SC_TOF;
758c2ecf20Sopenharmony_ci	ftm_writel(val, base + FTM_SC);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic inline void ftm_irq_enable(void __iomem *base)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	u32 val;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	val = ftm_readl(base + FTM_SC);
838c2ecf20Sopenharmony_ci	val |= FTM_SC_TOIE;
848c2ecf20Sopenharmony_ci	ftm_writel(val, base + FTM_SC);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic inline void ftm_irq_disable(void __iomem *base)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	u32 val;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	val = ftm_readl(base + FTM_SC);
928c2ecf20Sopenharmony_ci	val &= ~FTM_SC_TOIE;
938c2ecf20Sopenharmony_ci	ftm_writel(val, base + FTM_SC);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic inline void ftm_reset_counter(void __iomem *base)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	/*
998c2ecf20Sopenharmony_ci	 * The CNT register contains the FTM counter value.
1008c2ecf20Sopenharmony_ci	 * Reset clears the CNT register. Writing any value to COUNT
1018c2ecf20Sopenharmony_ci	 * updates the counter with its initial value, CNTIN.
1028c2ecf20Sopenharmony_ci	 */
1038c2ecf20Sopenharmony_ci	ftm_writel(0x00, base + FTM_CNT);
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic u64 notrace ftm_read_sched_clock(void)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	return ftm_readl(priv->clksrc_base + FTM_CNT);
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int ftm_set_next_event(unsigned long delta,
1128c2ecf20Sopenharmony_ci				struct clock_event_device *unused)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	/*
1158c2ecf20Sopenharmony_ci	 * The CNNIN and MOD are all double buffer registers, writing
1168c2ecf20Sopenharmony_ci	 * to the MOD register latches the value into a buffer. The MOD
1178c2ecf20Sopenharmony_ci	 * register is updated with the value of its write buffer with
1188c2ecf20Sopenharmony_ci	 * the following scenario:
1198c2ecf20Sopenharmony_ci	 * a, the counter source clock is diabled.
1208c2ecf20Sopenharmony_ci	 */
1218c2ecf20Sopenharmony_ci	ftm_counter_disable(priv->clkevt_base);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* Force the value of CNTIN to be loaded into the FTM counter */
1248c2ecf20Sopenharmony_ci	ftm_reset_counter(priv->clkevt_base);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/*
1278c2ecf20Sopenharmony_ci	 * The counter increments until the value of MOD is reached,
1288c2ecf20Sopenharmony_ci	 * at which point the counter is reloaded with the value of CNTIN.
1298c2ecf20Sopenharmony_ci	 * The TOF (the overflow flag) bit is set when the FTM counter
1308c2ecf20Sopenharmony_ci	 * changes from MOD to CNTIN. So we should using the delta - 1.
1318c2ecf20Sopenharmony_ci	 */
1328c2ecf20Sopenharmony_ci	ftm_writel(delta - 1, priv->clkevt_base + FTM_MOD);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	ftm_counter_enable(priv->clkevt_base);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	ftm_irq_enable(priv->clkevt_base);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return 0;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic int ftm_set_oneshot(struct clock_event_device *evt)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	ftm_counter_disable(priv->clkevt_base);
1448c2ecf20Sopenharmony_ci	return 0;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic int ftm_set_periodic(struct clock_event_device *evt)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	ftm_set_next_event(priv->periodic_cyc, evt);
1508c2ecf20Sopenharmony_ci	return 0;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic irqreturn_t ftm_evt_interrupt(int irq, void *dev_id)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct clock_event_device *evt = dev_id;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	ftm_irq_acknowledge(priv->clkevt_base);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (likely(clockevent_state_oneshot(evt))) {
1608c2ecf20Sopenharmony_ci		ftm_irq_disable(priv->clkevt_base);
1618c2ecf20Sopenharmony_ci		ftm_counter_disable(priv->clkevt_base);
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	evt->event_handler(evt);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic struct clock_event_device ftm_clockevent = {
1708c2ecf20Sopenharmony_ci	.name			= "Freescale ftm timer",
1718c2ecf20Sopenharmony_ci	.features		= CLOCK_EVT_FEAT_PERIODIC |
1728c2ecf20Sopenharmony_ci				  CLOCK_EVT_FEAT_ONESHOT,
1738c2ecf20Sopenharmony_ci	.set_state_periodic	= ftm_set_periodic,
1748c2ecf20Sopenharmony_ci	.set_state_oneshot	= ftm_set_oneshot,
1758c2ecf20Sopenharmony_ci	.set_next_event		= ftm_set_next_event,
1768c2ecf20Sopenharmony_ci	.rating			= 300,
1778c2ecf20Sopenharmony_ci};
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic int __init ftm_clockevent_init(unsigned long freq, int irq)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	int err;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	ftm_writel(0x00, priv->clkevt_base + FTM_CNTIN);
1848c2ecf20Sopenharmony_ci	ftm_writel(~0u, priv->clkevt_base + FTM_MOD);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	ftm_reset_counter(priv->clkevt_base);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	err = request_irq(irq, ftm_evt_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
1898c2ecf20Sopenharmony_ci			  "Freescale ftm timer", &ftm_clockevent);
1908c2ecf20Sopenharmony_ci	if (err) {
1918c2ecf20Sopenharmony_ci		pr_err("ftm: setup irq failed: %d\n", err);
1928c2ecf20Sopenharmony_ci		return err;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	ftm_clockevent.cpumask = cpumask_of(0);
1968c2ecf20Sopenharmony_ci	ftm_clockevent.irq = irq;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	clockevents_config_and_register(&ftm_clockevent,
1998c2ecf20Sopenharmony_ci					freq / (1 << priv->ps),
2008c2ecf20Sopenharmony_ci					1, 0xffff);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	ftm_counter_enable(priv->clkevt_base);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	return 0;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic int __init ftm_clocksource_init(unsigned long freq)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	int err;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	ftm_writel(0x00, priv->clksrc_base + FTM_CNTIN);
2128c2ecf20Sopenharmony_ci	ftm_writel(~0u, priv->clksrc_base + FTM_MOD);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	ftm_reset_counter(priv->clksrc_base);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	sched_clock_register(ftm_read_sched_clock, 16, freq / (1 << priv->ps));
2178c2ecf20Sopenharmony_ci	err = clocksource_mmio_init(priv->clksrc_base + FTM_CNT, "fsl-ftm",
2188c2ecf20Sopenharmony_ci				    freq / (1 << priv->ps), 300, 16,
2198c2ecf20Sopenharmony_ci				    clocksource_mmio_readl_up);
2208c2ecf20Sopenharmony_ci	if (err) {
2218c2ecf20Sopenharmony_ci		pr_err("ftm: init clock source mmio failed: %d\n", err);
2228c2ecf20Sopenharmony_ci		return err;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	ftm_counter_enable(priv->clksrc_base);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return 0;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic int __init __ftm_clk_init(struct device_node *np, char *cnt_name,
2318c2ecf20Sopenharmony_ci				 char *ftm_name)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct clk *clk;
2348c2ecf20Sopenharmony_ci	int err;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	clk = of_clk_get_by_name(np, cnt_name);
2378c2ecf20Sopenharmony_ci	if (IS_ERR(clk)) {
2388c2ecf20Sopenharmony_ci		pr_err("ftm: Cannot get \"%s\": %ld\n", cnt_name, PTR_ERR(clk));
2398c2ecf20Sopenharmony_ci		return PTR_ERR(clk);
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci	err = clk_prepare_enable(clk);
2428c2ecf20Sopenharmony_ci	if (err) {
2438c2ecf20Sopenharmony_ci		pr_err("ftm: clock failed to prepare+enable \"%s\": %d\n",
2448c2ecf20Sopenharmony_ci			cnt_name, err);
2458c2ecf20Sopenharmony_ci		return err;
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	clk = of_clk_get_by_name(np, ftm_name);
2498c2ecf20Sopenharmony_ci	if (IS_ERR(clk)) {
2508c2ecf20Sopenharmony_ci		pr_err("ftm: Cannot get \"%s\": %ld\n", ftm_name, PTR_ERR(clk));
2518c2ecf20Sopenharmony_ci		return PTR_ERR(clk);
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci	err = clk_prepare_enable(clk);
2548c2ecf20Sopenharmony_ci	if (err)
2558c2ecf20Sopenharmony_ci		pr_err("ftm: clock failed to prepare+enable \"%s\": %d\n",
2568c2ecf20Sopenharmony_ci			ftm_name, err);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return clk_get_rate(clk);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic unsigned long __init ftm_clk_init(struct device_node *np)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	long freq;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	freq = __ftm_clk_init(np, "ftm-evt-counter-en", "ftm-evt");
2668c2ecf20Sopenharmony_ci	if (freq <= 0)
2678c2ecf20Sopenharmony_ci		return 0;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	freq = __ftm_clk_init(np, "ftm-src-counter-en", "ftm-src");
2708c2ecf20Sopenharmony_ci	if (freq <= 0)
2718c2ecf20Sopenharmony_ci		return 0;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	return freq;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic int __init ftm_calc_closest_round_cyc(unsigned long freq)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	priv->ps = 0;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* The counter register is only using the lower 16 bits, and
2818c2ecf20Sopenharmony_ci	 * if the 'freq' value is to big here, then the periodic_cyc
2828c2ecf20Sopenharmony_ci	 * may exceed 0xFFFF.
2838c2ecf20Sopenharmony_ci	 */
2848c2ecf20Sopenharmony_ci	do {
2858c2ecf20Sopenharmony_ci		priv->periodic_cyc = DIV_ROUND_CLOSEST(freq,
2868c2ecf20Sopenharmony_ci						HZ * (1 << priv->ps++));
2878c2ecf20Sopenharmony_ci	} while (priv->periodic_cyc > 0xFFFF);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (priv->ps > FTM_PS_MAX) {
2908c2ecf20Sopenharmony_ci		pr_err("ftm: the prescaler is %lu > %d\n",
2918c2ecf20Sopenharmony_ci				priv->ps, FTM_PS_MAX);
2928c2ecf20Sopenharmony_ci		return -EINVAL;
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	return 0;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int __init ftm_timer_init(struct device_node *np)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	unsigned long freq;
3018c2ecf20Sopenharmony_ci	int ret, irq;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
3048c2ecf20Sopenharmony_ci	if (!priv)
3058c2ecf20Sopenharmony_ci		return -ENOMEM;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	ret = -ENXIO;
3088c2ecf20Sopenharmony_ci	priv->clkevt_base = of_iomap(np, 0);
3098c2ecf20Sopenharmony_ci	if (!priv->clkevt_base) {
3108c2ecf20Sopenharmony_ci		pr_err("ftm: unable to map event timer registers\n");
3118c2ecf20Sopenharmony_ci		goto err_clkevt;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	priv->clksrc_base = of_iomap(np, 1);
3158c2ecf20Sopenharmony_ci	if (!priv->clksrc_base) {
3168c2ecf20Sopenharmony_ci		pr_err("ftm: unable to map source timer registers\n");
3178c2ecf20Sopenharmony_ci		goto err_clksrc;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	ret = -EINVAL;
3218c2ecf20Sopenharmony_ci	irq = irq_of_parse_and_map(np, 0);
3228c2ecf20Sopenharmony_ci	if (irq <= 0) {
3238c2ecf20Sopenharmony_ci		pr_err("ftm: unable to get IRQ from DT, %d\n", irq);
3248c2ecf20Sopenharmony_ci		goto err;
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	priv->big_endian = of_property_read_bool(np, "big-endian");
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	freq = ftm_clk_init(np);
3308c2ecf20Sopenharmony_ci	if (!freq)
3318c2ecf20Sopenharmony_ci		goto err;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	ret = ftm_calc_closest_round_cyc(freq);
3348c2ecf20Sopenharmony_ci	if (ret)
3358c2ecf20Sopenharmony_ci		goto err;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	ret = ftm_clocksource_init(freq);
3388c2ecf20Sopenharmony_ci	if (ret)
3398c2ecf20Sopenharmony_ci		goto err;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	ret = ftm_clockevent_init(freq, irq);
3428c2ecf20Sopenharmony_ci	if (ret)
3438c2ecf20Sopenharmony_ci		goto err;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	return 0;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cierr:
3488c2ecf20Sopenharmony_ci	iounmap(priv->clksrc_base);
3498c2ecf20Sopenharmony_cierr_clksrc:
3508c2ecf20Sopenharmony_ci	iounmap(priv->clkevt_base);
3518c2ecf20Sopenharmony_cierr_clkevt:
3528c2ecf20Sopenharmony_ci	kfree(priv);
3538c2ecf20Sopenharmony_ci	return ret;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(flextimer, "fsl,ftm-timer", ftm_timer_init);
356