xref: /linux/drivers/clocksource/mps2-timer.c (revision e5c86679d5e864947a52fb31e45a425dea3e7fa9)
1 /*
2  * Copyright (C) 2015 ARM Limited
3  *
4  * Author: Vladimir Murzin <vladimir.murzin@arm.com>
5  *
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.
9  *
10  */
11 
12 #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
13 
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>
19 #include <linux/io.h>
20 #include <linux/irq.h>
21 #include <linux/of_address.h>
22 #include <linux/of.h>
23 #include <linux/of_irq.h>
24 #include <linux/sched_clock.h>
25 #include <linux/slab.h>
26 
27 #define TIMER_CTRL		0x0
28 #define TIMER_CTRL_ENABLE	BIT(0)
29 #define TIMER_CTRL_IE		BIT(3)
30 
31 #define TIMER_VALUE		0x4
32 #define TIMER_RELOAD		0x8
33 #define TIMER_INT		0xc
34 
35 struct clockevent_mps2 {
36 	void __iomem *reg;
37 	u32 clock_count_per_tick;
38 	struct clock_event_device clkevt;
39 };
40 
41 static void __iomem *sched_clock_base;
42 
43 static u64 notrace mps2_sched_read(void)
44 {
45 	return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
46 }
47 
48 static inline struct clockevent_mps2 *to_mps2_clkevt(struct clock_event_device *c)
49 {
50 	return container_of(c, struct clockevent_mps2, clkevt);
51 }
52 
53 static void clockevent_mps2_writel(u32 val, struct clock_event_device *c, u32 offset)
54 {
55 	writel_relaxed(val, to_mps2_clkevt(c)->reg + offset);
56 }
57 
58 static int mps2_timer_shutdown(struct clock_event_device *ce)
59 {
60 	clockevent_mps2_writel(0, ce, TIMER_RELOAD);
61 	clockevent_mps2_writel(0, ce, TIMER_CTRL);
62 
63 	return 0;
64 }
65 
66 static int mps2_timer_set_next_event(unsigned long next, struct clock_event_device *ce)
67 {
68 	clockevent_mps2_writel(next, ce, TIMER_VALUE);
69 	clockevent_mps2_writel(TIMER_CTRL_IE | TIMER_CTRL_ENABLE, ce, TIMER_CTRL);
70 
71 	return 0;
72 }
73 
74 static int mps2_timer_set_periodic(struct clock_event_device *ce)
75 {
76 	u32 clock_count_per_tick = to_mps2_clkevt(ce)->clock_count_per_tick;
77 
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);
81 
82 	return 0;
83 }
84 
85 static irqreturn_t mps2_timer_interrupt(int irq, void *dev_id)
86 {
87 	struct clockevent_mps2 *ce = dev_id;
88 	u32 status = readl_relaxed(ce->reg + TIMER_INT);
89 
90 	if (!status) {
91 		pr_warn("spurious interrupt\n");
92 		return IRQ_NONE;
93 	}
94 
95 	writel_relaxed(1, ce->reg + TIMER_INT);
96 
97 	ce->clkevt.event_handler(&ce->clkevt);
98 
99 	return IRQ_HANDLED;
100 }
101 
102 static int __init mps2_clockevent_init(struct device_node *np)
103 {
104 	void __iomem *base;
105 	struct clk *clk = NULL;
106 	struct clockevent_mps2 *ce;
107 	u32 rate;
108 	int irq, ret;
109 	const char *name = "mps2-clkevt";
110 
111 	ret = of_property_read_u32(np, "clock-frequency", &rate);
112 	if (ret) {
113 		clk = of_clk_get(np, 0);
114 		if (IS_ERR(clk)) {
115 			ret = PTR_ERR(clk);
116 			pr_err("failed to get clock for clockevent: %d\n", ret);
117 			goto out;
118 		}
119 
120 		ret = clk_prepare_enable(clk);
121 		if (ret) {
122 			pr_err("failed to enable clock for clockevent: %d\n", ret);
123 			goto out_clk_put;
124 		}
125 
126 		rate = clk_get_rate(clk);
127 	}
128 
129 	base = of_iomap(np, 0);
130 	if (!base) {
131 		ret = -EADDRNOTAVAIL;
132 		pr_err("failed to map register for clockevent: %d\n", ret);
133 		goto out_clk_disable;
134 	}
135 
136 	irq = irq_of_parse_and_map(np, 0);
137 	if (!irq) {
138 		ret = -ENOENT;
139 		pr_err("failed to get irq for clockevent: %d\n", ret);
140 		goto out_iounmap;
141 	}
142 
143 	ce = kzalloc(sizeof(*ce), GFP_KERNEL);
144 	if (!ce) {
145 		ret = -ENOMEM;
146 		goto out_iounmap;
147 	}
148 
149 	ce->reg = base;
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;
160 
161 	/* Ensure timer is disabled */
162 	writel_relaxed(0, base + TIMER_CTRL);
163 
164 	ret = request_irq(irq, mps2_timer_interrupt, IRQF_TIMER, name, ce);
165 	if (ret) {
166 		pr_err("failed to request irq for clockevent: %d\n", ret);
167 		goto out_kfree;
168 	}
169 
170 	clockevents_config_and_register(&ce->clkevt, rate, 0xf, 0xffffffff);
171 
172 	return 0;
173 
174 out_kfree:
175 	kfree(ce);
176 out_iounmap:
177 	iounmap(base);
178 out_clk_disable:
179 	/* clk_{disable, unprepare, put}() can handle NULL as a parameter */
180 	clk_disable_unprepare(clk);
181 out_clk_put:
182 	clk_put(clk);
183 out:
184 	return ret;
185 }
186 
187 static int __init mps2_clocksource_init(struct device_node *np)
188 {
189 	void __iomem *base;
190 	struct clk *clk = NULL;
191 	u32 rate;
192 	int ret;
193 	const char *name = "mps2-clksrc";
194 
195 	ret = of_property_read_u32(np, "clock-frequency", &rate);
196 	if (ret) {
197 		clk = of_clk_get(np, 0);
198 		if (IS_ERR(clk)) {
199 			ret = PTR_ERR(clk);
200 			pr_err("failed to get clock for clocksource: %d\n", ret);
201 			goto out;
202 		}
203 
204 		ret = clk_prepare_enable(clk);
205 		if (ret) {
206 			pr_err("failed to enable clock for clocksource: %d\n", ret);
207 			goto out_clk_put;
208 		}
209 
210 		rate = clk_get_rate(clk);
211 	}
212 
213 	base = of_iomap(np, 0);
214 	if (!base) {
215 		ret = -EADDRNOTAVAIL;
216 		pr_err("failed to map register for clocksource: %d\n", ret);
217 		goto out_clk_disable;
218 	}
219 
220 	/* Ensure timer is disabled */
221 	writel_relaxed(0, base + TIMER_CTRL);
222 
223 	/* ... and set it up as free-running clocksource */
224 	writel_relaxed(0xffffffff, base + TIMER_VALUE);
225 	writel_relaxed(0xffffffff, base + TIMER_RELOAD);
226 
227 	writel_relaxed(TIMER_CTRL_ENABLE, base + TIMER_CTRL);
228 
229 	ret = clocksource_mmio_init(base + TIMER_VALUE, name,
230 				    rate, 200, 32,
231 				    clocksource_mmio_readl_down);
232 	if (ret) {
233 		pr_err("failed to init clocksource: %d\n", ret);
234 		goto out_iounmap;
235 	}
236 
237 	sched_clock_base = base;
238 	sched_clock_register(mps2_sched_read, 32, rate);
239 
240 	return 0;
241 
242 out_iounmap:
243 	iounmap(base);
244 out_clk_disable:
245 	/* clk_{disable, unprepare, put}() can handle NULL as a parameter */
246 	clk_disable_unprepare(clk);
247 out_clk_put:
248 	clk_put(clk);
249 out:
250 	return ret;
251 }
252 
253 static int __init mps2_timer_init(struct device_node *np)
254 {
255 	static int has_clocksource, has_clockevent;
256 	int ret;
257 
258 	if (!has_clocksource) {
259 		ret = mps2_clocksource_init(np);
260 		if (!ret) {
261 			has_clocksource = 1;
262 			return 0;
263 		}
264 	}
265 
266 	if (!has_clockevent) {
267 		ret = mps2_clockevent_init(np);
268 		if (!ret) {
269 			has_clockevent = 1;
270 			return 0;
271 		}
272 	}
273 
274 	return 0;
275 }
276 
277 CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init);
278