2 * Copyright (C) 2015 ARM Limited
4 * Author: Vladimir Murzin <vladimir.murzin@arm.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 #include <linux/clk.h>
15 #include <linux/clockchips.h>
16 #include <linux/clocksource.h>
17 #include <linux/err.h>
18 #include <linux/interrupt.h>
20 #include <linux/irq.h>
21 #include <linux/of_address.h>
23 #include <linux/of_irq.h>
24 #include <linux/sched_clock.h>
25 #include <linux/slab.h>
27 #define TIMER_CTRL 0x0
28 #define TIMER_CTRL_ENABLE BIT(0)
29 #define TIMER_CTRL_IE BIT(3)
31 #define TIMER_VALUE 0x4
32 #define TIMER_RELOAD 0x8
35 struct clockevent_mps2
{
37 u32 clock_count_per_tick
;
38 struct clock_event_device clkevt
;
41 static void __iomem
*sched_clock_base
;
43 static u64 notrace
mps2_sched_read(void)
45 return ~readl_relaxed(sched_clock_base
+ TIMER_VALUE
);
48 static inline struct clockevent_mps2
*to_mps2_clkevt(struct clock_event_device
*c
)
50 return container_of(c
, struct clockevent_mps2
, clkevt
);
53 static void clockevent_mps2_writel(u32 val
, struct clock_event_device
*c
, u32 offset
)
55 writel_relaxed(val
, to_mps2_clkevt(c
)->reg
+ offset
);
58 static int mps2_timer_shutdown(struct clock_event_device
*ce
)
60 clockevent_mps2_writel(0, ce
, TIMER_RELOAD
);
61 clockevent_mps2_writel(0, ce
, TIMER_CTRL
);
66 static int mps2_timer_set_next_event(unsigned long next
, struct clock_event_device
*ce
)
68 clockevent_mps2_writel(next
, ce
, TIMER_VALUE
);
69 clockevent_mps2_writel(TIMER_CTRL_IE
| TIMER_CTRL_ENABLE
, ce
, TIMER_CTRL
);
74 static int mps2_timer_set_periodic(struct clock_event_device
*ce
)
76 u32 clock_count_per_tick
= to_mps2_clkevt(ce
)->clock_count_per_tick
;
78 clockevent_mps2_writel(clock_count_per_tick
, ce
, TIMER_RELOAD
);
79 clockevent_mps2_writel(clock_count_per_tick
, ce
, TIMER_VALUE
);
80 clockevent_mps2_writel(TIMER_CTRL_IE
| TIMER_CTRL_ENABLE
, ce
, TIMER_CTRL
);
85 static irqreturn_t
mps2_timer_interrupt(int irq
, void *dev_id
)
87 struct clockevent_mps2
*ce
= dev_id
;
88 u32 status
= readl_relaxed(ce
->reg
+ TIMER_INT
);
91 pr_warn("spurious interrupt\n");
95 writel_relaxed(1, ce
->reg
+ TIMER_INT
);
97 ce
->clkevt
.event_handler(&ce
->clkevt
);
102 static int __init
mps2_clockevent_init(struct device_node
*np
)
105 struct clk
*clk
= NULL
;
106 struct clockevent_mps2
*ce
;
109 const char *name
= "mps2-clkevt";
111 ret
= of_property_read_u32(np
, "clock-frequency", &rate
);
113 clk
= of_clk_get(np
, 0);
116 pr_err("failed to get clock for clockevent: %d\n", ret
);
120 ret
= clk_prepare_enable(clk
);
122 pr_err("failed to enable clock for clockevent: %d\n", ret
);
126 rate
= clk_get_rate(clk
);
129 base
= of_iomap(np
, 0);
131 ret
= -EADDRNOTAVAIL
;
132 pr_err("failed to map register for clockevent: %d\n", ret
);
133 goto out_clk_disable
;
136 irq
= irq_of_parse_and_map(np
, 0);
139 pr_err("failed to get irq for clockevent: %d\n", ret
);
143 ce
= kzalloc(sizeof(*ce
), GFP_KERNEL
);
150 ce
->clock_count_per_tick
= DIV_ROUND_CLOSEST(rate
, HZ
);
151 ce
->clkevt
.irq
= irq
;
152 ce
->clkevt
.name
= name
;
153 ce
->clkevt
.rating
= 200;
154 ce
->clkevt
.features
= CLOCK_EVT_FEAT_PERIODIC
| CLOCK_EVT_FEAT_ONESHOT
;
155 ce
->clkevt
.cpumask
= cpu_possible_mask
;
156 ce
->clkevt
.set_state_shutdown
= mps2_timer_shutdown
,
157 ce
->clkevt
.set_state_periodic
= mps2_timer_set_periodic
,
158 ce
->clkevt
.set_state_oneshot
= mps2_timer_shutdown
,
159 ce
->clkevt
.set_next_event
= mps2_timer_set_next_event
;
161 /* Ensure timer is disabled */
162 writel_relaxed(0, base
+ TIMER_CTRL
);
164 ret
= request_irq(irq
, mps2_timer_interrupt
, IRQF_TIMER
, name
, ce
);
166 pr_err("failed to request irq for clockevent: %d\n", ret
);
170 clockevents_config_and_register(&ce
->clkevt
, rate
, 0xf, 0xffffffff);
179 /* clk_{disable, unprepare, put}() can handle NULL as a parameter */
180 clk_disable_unprepare(clk
);
187 static int __init
mps2_clocksource_init(struct device_node
*np
)
190 struct clk
*clk
= NULL
;
193 const char *name
= "mps2-clksrc";
195 ret
= of_property_read_u32(np
, "clock-frequency", &rate
);
197 clk
= of_clk_get(np
, 0);
200 pr_err("failed to get clock for clocksource: %d\n", ret
);
204 ret
= clk_prepare_enable(clk
);
206 pr_err("failed to enable clock for clocksource: %d\n", ret
);
210 rate
= clk_get_rate(clk
);
213 base
= of_iomap(np
, 0);
215 ret
= -EADDRNOTAVAIL
;
216 pr_err("failed to map register for clocksource: %d\n", ret
);
217 goto out_clk_disable
;
220 /* Ensure timer is disabled */
221 writel_relaxed(0, base
+ TIMER_CTRL
);
223 /* ... and set it up as free-running clocksource */
224 writel_relaxed(0xffffffff, base
+ TIMER_VALUE
);
225 writel_relaxed(0xffffffff, base
+ TIMER_RELOAD
);
227 writel_relaxed(TIMER_CTRL_ENABLE
, base
+ TIMER_CTRL
);
229 ret
= clocksource_mmio_init(base
+ TIMER_VALUE
, name
,
231 clocksource_mmio_readl_down
);
233 pr_err("failed to init clocksource: %d\n", ret
);
237 sched_clock_base
= base
;
238 sched_clock_register(mps2_sched_read
, 32, rate
);
245 /* clk_{disable, unprepare, put}() can handle NULL as a parameter */
246 clk_disable_unprepare(clk
);
253 static int __init
mps2_timer_init(struct device_node
*np
)
255 static int has_clocksource
, has_clockevent
;
258 if (!has_clocksource
) {
259 ret
= mps2_clocksource_init(np
);
266 if (!has_clockevent
) {
267 ret
= mps2_clockevent_init(np
);
277 CLOCKSOURCE_OF_DECLARE(mps2_timer
, "arm,mps2-timer", mps2_timer_init
);