aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2017-03-24 17:32:35 -0400
committerDaniel Lezcano <daniel.lezcano@linaro.org>2017-04-07 10:23:08 -0400
commit28e71e2fe8fe6cdbd1bdc61601ea50d6423d3cf0 (patch)
tree745688ebc21f151d9a7bcbce406d77bd22f3dd3c /drivers/clocksource
parentf5bf0ee4ebf779e256bb710f638b4452d94e97fb (diff)
clocksource/drivers/fttmr010: Refactor to handle clock
The plain Faraday FTTMR010 timer needs a clock to figure out its tick rate, and the gemini reads it directly from the system controller set-up. Split the init function and add two paths for the two compatible-strings. We only support clocking using PCLK because of lack of documentation on how EXTCLK works. The Gemini still works like before, but we can also support a generic, clock-based version. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/timer-fttmr010.c119
1 files changed, 73 insertions, 46 deletions
diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c
index e37ec3d69a7e..b4a6f1e4bc54 100644
--- a/drivers/clocksource/timer-fttmr010.c
+++ b/drivers/clocksource/timer-fttmr010.c
@@ -16,17 +16,7 @@
16#include <linux/clockchips.h> 16#include <linux/clockchips.h>
17#include <linux/clocksource.h> 17#include <linux/clocksource.h>
18#include <linux/sched_clock.h> 18#include <linux/sched_clock.h>
19 19#include <linux/clk.h>
20/*
21 * Relevant registers in the global syscon
22 */
23#define GLOBAL_STATUS 0x04
24#define CPU_AHB_RATIO_MASK (0x3 << 18)
25#define CPU_AHB_1_1 (0x0 << 18)
26#define CPU_AHB_3_2 (0x1 << 18)
27#define CPU_AHB_24_13 (0x2 << 18)
28#define CPU_AHB_2_1 (0x3 << 18)
29#define REG_TO_AHB_SPEED(reg) ((((reg) >> 15) & 0x7) * 10 + 130)
30 20
31/* 21/*
32 * Register definitions for the timers 22 * Register definitions for the timers
@@ -189,23 +179,9 @@ static struct irqaction fttmr010_timer_irq = {
189 .handler = fttmr010_timer_interrupt, 179 .handler = fttmr010_timer_interrupt,
190}; 180};
191 181
192static int __init gemini_timer_of_init(struct device_node *np) 182static int __init fttmr010_timer_common_init(struct device_node *np)
193{ 183{
194 static struct regmap *map;
195 int irq; 184 int irq;
196 int ret;
197 u32 val;
198
199 map = syscon_regmap_lookup_by_phandle(np, "syscon");
200 if (IS_ERR(map)) {
201 pr_err("Can't get regmap for syscon handle");
202 return -ENODEV;
203 }
204 ret = regmap_read(map, GLOBAL_STATUS, &val);
205 if (ret) {
206 pr_err("Can't read syscon status register");
207 return -ENXIO;
208 }
209 185
210 base = of_iomap(np, 0); 186 base = of_iomap(np, 0);
211 if (!base) { 187 if (!base) {
@@ -219,26 +195,6 @@ static int __init gemini_timer_of_init(struct device_node *np)
219 return -EINVAL; 195 return -EINVAL;
220 } 196 }
221 197
222 tick_rate = REG_TO_AHB_SPEED(val) * 1000000;
223 printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000);
224
225 tick_rate /= 6; /* APB bus run AHB*(1/6) */
226
227 switch (val & CPU_AHB_RATIO_MASK) {
228 case CPU_AHB_1_1:
229 printk(KERN_CONT "(1/1)\n");
230 break;
231 case CPU_AHB_3_2:
232 printk(KERN_CONT "(3/2)\n");
233 break;
234 case CPU_AHB_24_13:
235 printk(KERN_CONT "(24/13)\n");
236 break;
237 case CPU_AHB_2_1:
238 printk(KERN_CONT "(2/1)\n");
239 break;
240 }
241
242 /* 198 /*
243 * Reset the interrupt mask and status 199 * Reset the interrupt mask and status
244 */ 200 */
@@ -273,4 +229,75 @@ static int __init gemini_timer_of_init(struct device_node *np)
273 229
274 return 0; 230 return 0;
275} 231}
232
233static int __init fttmr010_timer_of_init(struct device_node *np)
234{
235 /*
236 * These implementations require a clock reference.
237 * FIXME: we currently only support clocking using PCLK
238 * and using EXTCLK is not supported in the driver.
239 */
240 struct clk *clk;
241
242 clk = of_clk_get_by_name(np, "PCLK");
243 if (IS_ERR(clk)) {
244 pr_err("could not get PCLK");
245 return PTR_ERR(clk);
246 }
247 tick_rate = clk_get_rate(clk);
248
249 return fttmr010_timer_common_init(np);
250}
251CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_of_init);
252
253/*
254 * Gemini-specific: relevant registers in the global syscon
255 */
256#define GLOBAL_STATUS 0x04
257#define CPU_AHB_RATIO_MASK (0x3 << 18)
258#define CPU_AHB_1_1 (0x0 << 18)
259#define CPU_AHB_3_2 (0x1 << 18)
260#define CPU_AHB_24_13 (0x2 << 18)
261#define CPU_AHB_2_1 (0x3 << 18)
262#define REG_TO_AHB_SPEED(reg) ((((reg) >> 15) & 0x7) * 10 + 130)
263
264static int __init gemini_timer_of_init(struct device_node *np)
265{
266 static struct regmap *map;
267 int ret;
268 u32 val;
269
270 map = syscon_regmap_lookup_by_phandle(np, "syscon");
271 if (IS_ERR(map)) {
272 pr_err("Can't get regmap for syscon handle\n");
273 return -ENODEV;
274 }
275 ret = regmap_read(map, GLOBAL_STATUS, &val);
276 if (ret) {
277 pr_err("Can't read syscon status register\n");
278 return -ENXIO;
279 }
280
281 tick_rate = REG_TO_AHB_SPEED(val) * 1000000;
282 pr_info("Bus: %dMHz ", tick_rate / 1000000);
283
284 tick_rate /= 6; /* APB bus run AHB*(1/6) */
285
286 switch (val & CPU_AHB_RATIO_MASK) {
287 case CPU_AHB_1_1:
288 pr_cont("(1/1)\n");
289 break;
290 case CPU_AHB_3_2:
291 pr_cont("(3/2)\n");
292 break;
293 case CPU_AHB_24_13:
294 pr_cont("(24/13)\n");
295 break;
296 case CPU_AHB_2_1:
297 pr_cont("(2/1)\n");
298 break;
299 }
300
301 return fttmr010_timer_common_init(np);
302}
276CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", gemini_timer_of_init); 303CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", gemini_timer_of_init);