1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * arch/arm/mach-vt8500/timer.c
5 * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
6 * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
10 * This file is copied and modified from the original timer.c provided by
11 * Alexey Charkov. Minor changes have been made for Device Tree Support.
15 #include <linux/irq.h>
16 #include <linux/interrupt.h>
17 #include <linux/clocksource.h>
18 #include <linux/clockchips.h>
19 #include <linux/delay.h>
22 #include <linux/of_address.h>
23 #include <linux/of_irq.h>
25 #define VT8500_TIMER_OFFSET 0x0100
26 #define VT8500_TIMER_HZ 3000000
27 #define TIMER_MATCH_VAL 0x0000
28 #define TIMER_COUNT_VAL 0x0010
29 #define TIMER_STATUS_VAL 0x0014
30 #define TIMER_IER_VAL 0x001c /* interrupt enable */
31 #define TIMER_CTRL_VAL 0x0020
32 #define TIMER_AS_VAL 0x0024 /* access status */
33 #define TIMER_COUNT_R_ACTIVE (1 << 5) /* not ready for read */
34 #define TIMER_COUNT_W_ACTIVE (1 << 4) /* not ready for write */
35 #define TIMER_MATCH_W_ACTIVE (1 << 0) /* not ready for write */
37 #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
39 #define MIN_OSCR_DELTA 16
41 static void __iomem
*regbase
;
43 static u64
vt8500_timer_read(struct clocksource
*cs
)
45 int loops
= msecs_to_loops(10);
46 writel(3, regbase
+ TIMER_CTRL_VAL
);
47 while ((readl((regbase
+ TIMER_AS_VAL
)) & TIMER_COUNT_R_ACTIVE
)
50 return readl(regbase
+ TIMER_COUNT_VAL
);
53 static struct clocksource clocksource
= {
54 .name
= "vt8500_timer",
56 .read
= vt8500_timer_read
,
57 .mask
= CLOCKSOURCE_MASK(32),
58 .flags
= CLOCK_SOURCE_IS_CONTINUOUS
,
61 static int vt8500_timer_set_next_event(unsigned long cycles
,
62 struct clock_event_device
*evt
)
64 int loops
= msecs_to_loops(10);
65 u64 alarm
= clocksource
.read(&clocksource
) + cycles
;
66 while ((readl(regbase
+ TIMER_AS_VAL
) & TIMER_MATCH_W_ACTIVE
)
69 writel((unsigned long)alarm
, regbase
+ TIMER_MATCH_VAL
);
71 if ((signed)(alarm
- clocksource
.read(&clocksource
)) <= MIN_OSCR_DELTA
)
74 writel(1, regbase
+ TIMER_IER_VAL
);
79 static int vt8500_shutdown(struct clock_event_device
*evt
)
81 writel(readl(regbase
+ TIMER_CTRL_VAL
) | 1, regbase
+ TIMER_CTRL_VAL
);
82 writel(0, regbase
+ TIMER_IER_VAL
);
86 static struct clock_event_device clockevent
= {
87 .name
= "vt8500_timer",
88 .features
= CLOCK_EVT_FEAT_ONESHOT
,
90 .set_next_event
= vt8500_timer_set_next_event
,
91 .set_state_shutdown
= vt8500_shutdown
,
92 .set_state_oneshot
= vt8500_shutdown
,
95 static irqreturn_t
vt8500_timer_interrupt(int irq
, void *dev_id
)
97 struct clock_event_device
*evt
= dev_id
;
98 writel(0xf, regbase
+ TIMER_STATUS_VAL
);
99 evt
->event_handler(evt
);
104 static struct irqaction irq
= {
105 .name
= "vt8500_timer",
106 .flags
= IRQF_TIMER
| IRQF_IRQPOLL
,
107 .handler
= vt8500_timer_interrupt
,
108 .dev_id
= &clockevent
,
111 static int __init
vt8500_timer_init(struct device_node
*np
)
115 regbase
= of_iomap(np
, 0);
117 pr_err("%s: Missing iobase description in Device Tree\n",
122 timer_irq
= irq_of_parse_and_map(np
, 0);
124 pr_err("%s: Missing irq description in Device Tree\n",
129 writel(1, regbase
+ TIMER_CTRL_VAL
);
130 writel(0xf, regbase
+ TIMER_STATUS_VAL
);
131 writel(~0, regbase
+ TIMER_MATCH_VAL
);
133 ret
= clocksource_register_hz(&clocksource
, VT8500_TIMER_HZ
);
135 pr_err("%s: clocksource_register failed for %s\n",
136 __func__
, clocksource
.name
);
140 clockevent
.cpumask
= cpumask_of(0);
142 ret
= setup_irq(timer_irq
, &irq
);
144 pr_err("%s: setup_irq failed for %s\n", __func__
,
149 clockevents_config_and_register(&clockevent
, VT8500_TIMER_HZ
,
150 MIN_OSCR_DELTA
* 2, 0xf0000000);
155 TIMER_OF_DECLARE(vt8500
, "via,vt8500-timer", vt8500_timer_init
);