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