1*85c5aafdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0
29d8d47eaSDaniel Lezcano /*
39d8d47eaSDaniel Lezcano  * Clocksource driver for NXP LPC32xx/18xx/43xx timer
49d8d47eaSDaniel Lezcano  *
59d8d47eaSDaniel Lezcano  * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
69d8d47eaSDaniel Lezcano  *
79d8d47eaSDaniel Lezcano  * Based on:
89d8d47eaSDaniel Lezcano  * time-efm32 Copyright (C) 2013 Pengutronix
99d8d47eaSDaniel Lezcano  * mach-lpc32xx/timer.c Copyright (C) 2009 - 2010 NXP Semiconductors
109d8d47eaSDaniel Lezcano  */
119d8d47eaSDaniel Lezcano 
129d8d47eaSDaniel Lezcano #define pr_fmt(fmt) "%s: " fmt, __func__
139d8d47eaSDaniel Lezcano 
149d8d47eaSDaniel Lezcano #include <linux/clk.h>
159d8d47eaSDaniel Lezcano #include <linux/clockchips.h>
169d8d47eaSDaniel Lezcano #include <linux/clocksource.h>
179d8d47eaSDaniel Lezcano #include <linux/delay.h>
189d8d47eaSDaniel Lezcano #include <linux/interrupt.h>
199d8d47eaSDaniel Lezcano #include <linux/irq.h>
209d8d47eaSDaniel Lezcano #include <linux/kernel.h>
219d8d47eaSDaniel Lezcano #include <linux/of.h>
229d8d47eaSDaniel Lezcano #include <linux/of_address.h>
239d8d47eaSDaniel Lezcano #include <linux/of_irq.h>
249d8d47eaSDaniel Lezcano #include <linux/sched_clock.h>
259d8d47eaSDaniel Lezcano 
269d8d47eaSDaniel Lezcano #define LPC32XX_TIMER_IR		0x000
279d8d47eaSDaniel Lezcano #define  LPC32XX_TIMER_IR_MR0INT	BIT(0)
289d8d47eaSDaniel Lezcano #define LPC32XX_TIMER_TCR		0x004
299d8d47eaSDaniel Lezcano #define  LPC32XX_TIMER_TCR_CEN		BIT(0)
309d8d47eaSDaniel Lezcano #define  LPC32XX_TIMER_TCR_CRST		BIT(1)
319d8d47eaSDaniel Lezcano #define LPC32XX_TIMER_TC		0x008
329d8d47eaSDaniel Lezcano #define LPC32XX_TIMER_PR		0x00c
339d8d47eaSDaniel Lezcano #define LPC32XX_TIMER_MCR		0x014
349d8d47eaSDaniel Lezcano #define  LPC32XX_TIMER_MCR_MR0I		BIT(0)
359d8d47eaSDaniel Lezcano #define  LPC32XX_TIMER_MCR_MR0R		BIT(1)
369d8d47eaSDaniel Lezcano #define  LPC32XX_TIMER_MCR_MR0S		BIT(2)
379d8d47eaSDaniel Lezcano #define LPC32XX_TIMER_MR0		0x018
389d8d47eaSDaniel Lezcano #define LPC32XX_TIMER_CTCR		0x070
399d8d47eaSDaniel Lezcano 
409d8d47eaSDaniel Lezcano struct lpc32xx_clock_event_ddata {
419d8d47eaSDaniel Lezcano 	struct clock_event_device evtdev;
429d8d47eaSDaniel Lezcano 	void __iomem *base;
439d8d47eaSDaniel Lezcano 	u32 ticks_per_jiffy;
449d8d47eaSDaniel Lezcano };
459d8d47eaSDaniel Lezcano 
469d8d47eaSDaniel Lezcano /* Needed for the sched clock */
479d8d47eaSDaniel Lezcano static void __iomem *clocksource_timer_counter;
489d8d47eaSDaniel Lezcano 
lpc32xx_read_sched_clock(void)499d8d47eaSDaniel Lezcano static u64 notrace lpc32xx_read_sched_clock(void)
509d8d47eaSDaniel Lezcano {
519d8d47eaSDaniel Lezcano 	return readl(clocksource_timer_counter);
529d8d47eaSDaniel Lezcano }
539d8d47eaSDaniel Lezcano 
lpc32xx_delay_timer_read(void)549d8d47eaSDaniel Lezcano static unsigned long lpc32xx_delay_timer_read(void)
559d8d47eaSDaniel Lezcano {
569d8d47eaSDaniel Lezcano 	return readl(clocksource_timer_counter);
579d8d47eaSDaniel Lezcano }
589d8d47eaSDaniel Lezcano 
599d8d47eaSDaniel Lezcano static struct delay_timer lpc32xx_delay_timer = {
609d8d47eaSDaniel Lezcano 	.read_current_timer = lpc32xx_delay_timer_read,
619d8d47eaSDaniel Lezcano };
629d8d47eaSDaniel Lezcano 
lpc32xx_clkevt_next_event(unsigned long delta,struct clock_event_device * evtdev)639d8d47eaSDaniel Lezcano static int lpc32xx_clkevt_next_event(unsigned long delta,
649d8d47eaSDaniel Lezcano 				     struct clock_event_device *evtdev)
659d8d47eaSDaniel Lezcano {
669d8d47eaSDaniel Lezcano 	struct lpc32xx_clock_event_ddata *ddata =
679d8d47eaSDaniel Lezcano 		container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
689d8d47eaSDaniel Lezcano 
699d8d47eaSDaniel Lezcano 	/*
709d8d47eaSDaniel Lezcano 	 * Place timer in reset and program the delta in the match
719d8d47eaSDaniel Lezcano 	 * channel 0 (MR0). When the timer counter matches the value
729d8d47eaSDaniel Lezcano 	 * in MR0 register the match will trigger an interrupt.
739d8d47eaSDaniel Lezcano 	 * After setup the timer is released from reset and enabled.
749d8d47eaSDaniel Lezcano 	 */
759d8d47eaSDaniel Lezcano 	writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
769d8d47eaSDaniel Lezcano 	writel_relaxed(delta, ddata->base + LPC32XX_TIMER_MR0);
779d8d47eaSDaniel Lezcano 	writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);
789d8d47eaSDaniel Lezcano 
799d8d47eaSDaniel Lezcano 	return 0;
809d8d47eaSDaniel Lezcano }
819d8d47eaSDaniel Lezcano 
lpc32xx_clkevt_shutdown(struct clock_event_device * evtdev)829d8d47eaSDaniel Lezcano static int lpc32xx_clkevt_shutdown(struct clock_event_device *evtdev)
839d8d47eaSDaniel Lezcano {
849d8d47eaSDaniel Lezcano 	struct lpc32xx_clock_event_ddata *ddata =
859d8d47eaSDaniel Lezcano 		container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
869d8d47eaSDaniel Lezcano 
879d8d47eaSDaniel Lezcano 	/* Disable the timer */
889d8d47eaSDaniel Lezcano 	writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR);
899d8d47eaSDaniel Lezcano 
909d8d47eaSDaniel Lezcano 	return 0;
919d8d47eaSDaniel Lezcano }
929d8d47eaSDaniel Lezcano 
lpc32xx_clkevt_oneshot(struct clock_event_device * evtdev)939d8d47eaSDaniel Lezcano static int lpc32xx_clkevt_oneshot(struct clock_event_device *evtdev)
949d8d47eaSDaniel Lezcano {
959d8d47eaSDaniel Lezcano 	struct lpc32xx_clock_event_ddata *ddata =
969d8d47eaSDaniel Lezcano 		container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
979d8d47eaSDaniel Lezcano 
989d8d47eaSDaniel Lezcano 	/*
999d8d47eaSDaniel Lezcano 	 * When using oneshot, we must also disable the timer
1009d8d47eaSDaniel Lezcano 	 * to wait for the first call to set_next_event().
1019d8d47eaSDaniel Lezcano 	 */
1029d8d47eaSDaniel Lezcano 	writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR);
1039d8d47eaSDaniel Lezcano 
1049d8d47eaSDaniel Lezcano 	/* Enable interrupt, reset on match and stop on match (MCR). */
1059d8d47eaSDaniel Lezcano 	writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
1069d8d47eaSDaniel Lezcano 		       LPC32XX_TIMER_MCR_MR0S, ddata->base + LPC32XX_TIMER_MCR);
1079d8d47eaSDaniel Lezcano 	return 0;
1089d8d47eaSDaniel Lezcano }
1099d8d47eaSDaniel Lezcano 
lpc32xx_clkevt_periodic(struct clock_event_device * evtdev)1109d8d47eaSDaniel Lezcano static int lpc32xx_clkevt_periodic(struct clock_event_device *evtdev)
1119d8d47eaSDaniel Lezcano {
1129d8d47eaSDaniel Lezcano 	struct lpc32xx_clock_event_ddata *ddata =
1139d8d47eaSDaniel Lezcano 		container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
1149d8d47eaSDaniel Lezcano 
1159d8d47eaSDaniel Lezcano 	/* Enable interrupt and reset on match. */
1169d8d47eaSDaniel Lezcano 	writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R,
1179d8d47eaSDaniel Lezcano 		       ddata->base + LPC32XX_TIMER_MCR);
1189d8d47eaSDaniel Lezcano 
1199d8d47eaSDaniel Lezcano 	/*
1209d8d47eaSDaniel Lezcano 	 * Place timer in reset and program the delta in the match
1219d8d47eaSDaniel Lezcano 	 * channel 0 (MR0).
1229d8d47eaSDaniel Lezcano 	 */
1239d8d47eaSDaniel Lezcano 	writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
1249d8d47eaSDaniel Lezcano 	writel_relaxed(ddata->ticks_per_jiffy, ddata->base + LPC32XX_TIMER_MR0);
1259d8d47eaSDaniel Lezcano 	writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);
1269d8d47eaSDaniel Lezcano 
1279d8d47eaSDaniel Lezcano 	return 0;
1289d8d47eaSDaniel Lezcano }
1299d8d47eaSDaniel Lezcano 
lpc32xx_clock_event_handler(int irq,void * dev_id)1309d8d47eaSDaniel Lezcano static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id)
1319d8d47eaSDaniel Lezcano {
1329d8d47eaSDaniel Lezcano 	struct lpc32xx_clock_event_ddata *ddata = dev_id;
1339d8d47eaSDaniel Lezcano 
1349d8d47eaSDaniel Lezcano 	/* Clear match on channel 0 */
1359d8d47eaSDaniel Lezcano 	writel_relaxed(LPC32XX_TIMER_IR_MR0INT, ddata->base + LPC32XX_TIMER_IR);
1369d8d47eaSDaniel Lezcano 
1379d8d47eaSDaniel Lezcano 	ddata->evtdev.event_handler(&ddata->evtdev);
1389d8d47eaSDaniel Lezcano 
1399d8d47eaSDaniel Lezcano 	return IRQ_HANDLED;
1409d8d47eaSDaniel Lezcano }
1419d8d47eaSDaniel Lezcano 
1429d8d47eaSDaniel Lezcano static struct lpc32xx_clock_event_ddata lpc32xx_clk_event_ddata = {
1439d8d47eaSDaniel Lezcano 	.evtdev = {
1449d8d47eaSDaniel Lezcano 		.name			= "lpc3220 clockevent",
1459d8d47eaSDaniel Lezcano 		.features		= CLOCK_EVT_FEAT_ONESHOT |
1469d8d47eaSDaniel Lezcano 					  CLOCK_EVT_FEAT_PERIODIC,
1479d8d47eaSDaniel Lezcano 		.rating			= 300,
1489d8d47eaSDaniel Lezcano 		.set_next_event		= lpc32xx_clkevt_next_event,
1499d8d47eaSDaniel Lezcano 		.set_state_shutdown	= lpc32xx_clkevt_shutdown,
1509d8d47eaSDaniel Lezcano 		.set_state_oneshot	= lpc32xx_clkevt_oneshot,
1519d8d47eaSDaniel Lezcano 		.set_state_periodic	= lpc32xx_clkevt_periodic,
1529d8d47eaSDaniel Lezcano 	},
1539d8d47eaSDaniel Lezcano };
1549d8d47eaSDaniel Lezcano 
lpc32xx_clocksource_init(struct device_node * np)1559d8d47eaSDaniel Lezcano static int __init lpc32xx_clocksource_init(struct device_node *np)
1569d8d47eaSDaniel Lezcano {
1579d8d47eaSDaniel Lezcano 	void __iomem *base;
1589d8d47eaSDaniel Lezcano 	unsigned long rate;
1599d8d47eaSDaniel Lezcano 	struct clk *clk;
1609d8d47eaSDaniel Lezcano 	int ret;
1619d8d47eaSDaniel Lezcano 
1629d8d47eaSDaniel Lezcano 	clk = of_clk_get_by_name(np, "timerclk");
1639d8d47eaSDaniel Lezcano 	if (IS_ERR(clk)) {
1649d8d47eaSDaniel Lezcano 		pr_err("clock get failed (%ld)\n", PTR_ERR(clk));
1659d8d47eaSDaniel Lezcano 		return PTR_ERR(clk);
1669d8d47eaSDaniel Lezcano 	}
1679d8d47eaSDaniel Lezcano 
1689d8d47eaSDaniel Lezcano 	ret = clk_prepare_enable(clk);
1699d8d47eaSDaniel Lezcano 	if (ret) {
1709d8d47eaSDaniel Lezcano 		pr_err("clock enable failed (%d)\n", ret);
1719d8d47eaSDaniel Lezcano 		goto err_clk_enable;
1729d8d47eaSDaniel Lezcano 	}
1739d8d47eaSDaniel Lezcano 
1749d8d47eaSDaniel Lezcano 	base = of_iomap(np, 0);
1759d8d47eaSDaniel Lezcano 	if (!base) {
1769d8d47eaSDaniel Lezcano 		pr_err("unable to map registers\n");
1779d8d47eaSDaniel Lezcano 		ret = -EADDRNOTAVAIL;
1789d8d47eaSDaniel Lezcano 		goto err_iomap;
1799d8d47eaSDaniel Lezcano 	}
1809d8d47eaSDaniel Lezcano 
1819d8d47eaSDaniel Lezcano 	/*
1829d8d47eaSDaniel Lezcano 	 * Disable and reset timer then set it to free running timer
1839d8d47eaSDaniel Lezcano 	 * mode (CTCR) with no prescaler (PR) or match operations (MCR).
1849d8d47eaSDaniel Lezcano 	 * After setup the timer is released from reset and enabled.
1859d8d47eaSDaniel Lezcano 	 */
1869d8d47eaSDaniel Lezcano 	writel_relaxed(LPC32XX_TIMER_TCR_CRST, base + LPC32XX_TIMER_TCR);
1879d8d47eaSDaniel Lezcano 	writel_relaxed(0, base + LPC32XX_TIMER_PR);
1889d8d47eaSDaniel Lezcano 	writel_relaxed(0, base + LPC32XX_TIMER_MCR);
1899d8d47eaSDaniel Lezcano 	writel_relaxed(0, base + LPC32XX_TIMER_CTCR);
1909d8d47eaSDaniel Lezcano 	writel_relaxed(LPC32XX_TIMER_TCR_CEN, base + LPC32XX_TIMER_TCR);
1919d8d47eaSDaniel Lezcano 
1929d8d47eaSDaniel Lezcano 	rate = clk_get_rate(clk);
1939d8d47eaSDaniel Lezcano 	ret = clocksource_mmio_init(base + LPC32XX_TIMER_TC, "lpc3220 timer",
1949d8d47eaSDaniel Lezcano 				    rate, 300, 32, clocksource_mmio_readl_up);
1959d8d47eaSDaniel Lezcano 	if (ret) {
1969d8d47eaSDaniel Lezcano 		pr_err("failed to init clocksource (%d)\n", ret);
1979d8d47eaSDaniel Lezcano 		goto err_clocksource_init;
1989d8d47eaSDaniel Lezcano 	}
1999d8d47eaSDaniel Lezcano 
2009d8d47eaSDaniel Lezcano 	clocksource_timer_counter = base + LPC32XX_TIMER_TC;
2019d8d47eaSDaniel Lezcano 	lpc32xx_delay_timer.freq = rate;
2029d8d47eaSDaniel Lezcano 	register_current_timer_delay(&lpc32xx_delay_timer);
2039d8d47eaSDaniel Lezcano 	sched_clock_register(lpc32xx_read_sched_clock, 32, rate);
2049d8d47eaSDaniel Lezcano 
2059d8d47eaSDaniel Lezcano 	return 0;
2069d8d47eaSDaniel Lezcano 
2079d8d47eaSDaniel Lezcano err_clocksource_init:
2089d8d47eaSDaniel Lezcano 	iounmap(base);
2099d8d47eaSDaniel Lezcano err_iomap:
2109d8d47eaSDaniel Lezcano 	clk_disable_unprepare(clk);
2119d8d47eaSDaniel Lezcano err_clk_enable:
2129d8d47eaSDaniel Lezcano 	clk_put(clk);
2139d8d47eaSDaniel Lezcano 	return ret;
2149d8d47eaSDaniel Lezcano }
2159d8d47eaSDaniel Lezcano 
lpc32xx_clockevent_init(struct device_node * np)2169d8d47eaSDaniel Lezcano static int __init lpc32xx_clockevent_init(struct device_node *np)
2179d8d47eaSDaniel Lezcano {
2189d8d47eaSDaniel Lezcano 	void __iomem *base;
2199d8d47eaSDaniel Lezcano 	unsigned long rate;
2209d8d47eaSDaniel Lezcano 	struct clk *clk;
2219d8d47eaSDaniel Lezcano 	int ret, irq;
2229d8d47eaSDaniel Lezcano 
2239d8d47eaSDaniel Lezcano 	clk = of_clk_get_by_name(np, "timerclk");
2249d8d47eaSDaniel Lezcano 	if (IS_ERR(clk)) {
2259d8d47eaSDaniel Lezcano 		pr_err("clock get failed (%ld)\n", PTR_ERR(clk));
2269d8d47eaSDaniel Lezcano 		return PTR_ERR(clk);
2279d8d47eaSDaniel Lezcano 	}
2289d8d47eaSDaniel Lezcano 
2299d8d47eaSDaniel Lezcano 	ret = clk_prepare_enable(clk);
2309d8d47eaSDaniel Lezcano 	if (ret) {
2319d8d47eaSDaniel Lezcano 		pr_err("clock enable failed (%d)\n", ret);
2329d8d47eaSDaniel Lezcano 		goto err_clk_enable;
2339d8d47eaSDaniel Lezcano 	}
2349d8d47eaSDaniel Lezcano 
2359d8d47eaSDaniel Lezcano 	base = of_iomap(np, 0);
2369d8d47eaSDaniel Lezcano 	if (!base) {
2379d8d47eaSDaniel Lezcano 		pr_err("unable to map registers\n");
2389d8d47eaSDaniel Lezcano 		ret = -EADDRNOTAVAIL;
2399d8d47eaSDaniel Lezcano 		goto err_iomap;
2409d8d47eaSDaniel Lezcano 	}
2419d8d47eaSDaniel Lezcano 
2429d8d47eaSDaniel Lezcano 	irq = irq_of_parse_and_map(np, 0);
2439d8d47eaSDaniel Lezcano 	if (!irq) {
2449d8d47eaSDaniel Lezcano 		pr_err("get irq failed\n");
2459d8d47eaSDaniel Lezcano 		ret = -ENOENT;
2469d8d47eaSDaniel Lezcano 		goto err_irq;
2479d8d47eaSDaniel Lezcano 	}
2489d8d47eaSDaniel Lezcano 
2499d8d47eaSDaniel Lezcano 	/*
2509d8d47eaSDaniel Lezcano 	 * Disable timer and clear any pending interrupt (IR) on match
2519d8d47eaSDaniel Lezcano 	 * channel 0 (MR0). Clear the prescaler as it's not used.
2529d8d47eaSDaniel Lezcano 	 */
2539d8d47eaSDaniel Lezcano 	writel_relaxed(0, base + LPC32XX_TIMER_TCR);
2549d8d47eaSDaniel Lezcano 	writel_relaxed(0, base + LPC32XX_TIMER_PR);
2559d8d47eaSDaniel Lezcano 	writel_relaxed(0, base + LPC32XX_TIMER_CTCR);
2569d8d47eaSDaniel Lezcano 	writel_relaxed(LPC32XX_TIMER_IR_MR0INT, base + LPC32XX_TIMER_IR);
2579d8d47eaSDaniel Lezcano 
2589d8d47eaSDaniel Lezcano 	rate = clk_get_rate(clk);
2599d8d47eaSDaniel Lezcano 	lpc32xx_clk_event_ddata.base = base;
2609d8d47eaSDaniel Lezcano 	lpc32xx_clk_event_ddata.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
2619d8d47eaSDaniel Lezcano 	clockevents_config_and_register(&lpc32xx_clk_event_ddata.evtdev,
2629d8d47eaSDaniel Lezcano 					rate, 1, -1);
2639d8d47eaSDaniel Lezcano 
2649d8d47eaSDaniel Lezcano 	ret = request_irq(irq, lpc32xx_clock_event_handler,
2659d8d47eaSDaniel Lezcano 			  IRQF_TIMER | IRQF_IRQPOLL, "lpc3220 clockevent",
2669d8d47eaSDaniel Lezcano 			  &lpc32xx_clk_event_ddata);
2679d8d47eaSDaniel Lezcano 	if (ret) {
2689d8d47eaSDaniel Lezcano 		pr_err("request irq failed\n");
2699d8d47eaSDaniel Lezcano 		goto err_irq;
2709d8d47eaSDaniel Lezcano 	}
2719d8d47eaSDaniel Lezcano 
2729d8d47eaSDaniel Lezcano 	return 0;
2739d8d47eaSDaniel Lezcano 
2749d8d47eaSDaniel Lezcano err_irq:
2759d8d47eaSDaniel Lezcano 	iounmap(base);
2769d8d47eaSDaniel Lezcano err_iomap:
2779d8d47eaSDaniel Lezcano 	clk_disable_unprepare(clk);
2789d8d47eaSDaniel Lezcano err_clk_enable:
2799d8d47eaSDaniel Lezcano 	clk_put(clk);
2809d8d47eaSDaniel Lezcano 	return ret;
2819d8d47eaSDaniel Lezcano }
2829d8d47eaSDaniel Lezcano 
2839d8d47eaSDaniel Lezcano /*
2849d8d47eaSDaniel Lezcano  * This function asserts that we have exactly one clocksource and one
2859d8d47eaSDaniel Lezcano  * clock_event_device in the end.
2869d8d47eaSDaniel Lezcano  */
lpc32xx_timer_init(struct device_node * np)2879d8d47eaSDaniel Lezcano static int __init lpc32xx_timer_init(struct device_node *np)
2889d8d47eaSDaniel Lezcano {
2899d8d47eaSDaniel Lezcano 	static int has_clocksource, has_clockevent;
2909d8d47eaSDaniel Lezcano 	int ret = 0;
2919d8d47eaSDaniel Lezcano 
2929d8d47eaSDaniel Lezcano 	if (!has_clocksource) {
2939d8d47eaSDaniel Lezcano 		ret = lpc32xx_clocksource_init(np);
2949d8d47eaSDaniel Lezcano 		if (!ret) {
2959d8d47eaSDaniel Lezcano 			has_clocksource = 1;
2969d8d47eaSDaniel Lezcano 			return 0;
2979d8d47eaSDaniel Lezcano 		}
2989d8d47eaSDaniel Lezcano 	}
2999d8d47eaSDaniel Lezcano 
3009d8d47eaSDaniel Lezcano 	if (!has_clockevent) {
3019d8d47eaSDaniel Lezcano 		ret = lpc32xx_clockevent_init(np);
3029d8d47eaSDaniel Lezcano 		if (!ret) {
3039d8d47eaSDaniel Lezcano 			has_clockevent = 1;
3049d8d47eaSDaniel Lezcano 			return 0;
3059d8d47eaSDaniel Lezcano 		}
3069d8d47eaSDaniel Lezcano 	}
3079d8d47eaSDaniel Lezcano 
3089d8d47eaSDaniel Lezcano 	return ret;
3099d8d47eaSDaniel Lezcano }
3109d8d47eaSDaniel Lezcano TIMER_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init);
311