diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2017-03-25 00:32:35 +0300 |
---|---|---|
committer | Daniel Lezcano <daniel.lezcano@linaro.org> | 2017-04-07 17:23:08 +0300 |
commit | 28e71e2fe8fe6cdbd1bdc61601ea50d6423d3cf0 (patch) | |
tree | 745688ebc21f151d9a7bcbce406d77bd22f3dd3c /drivers/clocksource/timer-fttmr010.c | |
parent | f5bf0ee4ebf779e256bb710f638b4452d94e97fb (diff) | |
download | linux-28e71e2fe8fe6cdbd1bdc61601ea50d6423d3cf0.tar.xz |
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/timer-fttmr010.c')
-rw-r--r-- | drivers/clocksource/timer-fttmr010.c | 119 |
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 @@ #include <linux/clockchips.h> #include <linux/clocksource.h> #include <linux/sched_clock.h> - -/* - * Relevant registers in the global syscon - */ -#define GLOBAL_STATUS 0x04 -#define CPU_AHB_RATIO_MASK (0x3 << 18) -#define CPU_AHB_1_1 (0x0 << 18) -#define CPU_AHB_3_2 (0x1 << 18) -#define CPU_AHB_24_13 (0x2 << 18) -#define CPU_AHB_2_1 (0x3 << 18) -#define REG_TO_AHB_SPEED(reg) ((((reg) >> 15) & 0x7) * 10 + 130) +#include <linux/clk.h> /* * Register definitions for the timers @@ -189,23 +179,9 @@ static struct irqaction fttmr010_timer_irq = { .handler = fttmr010_timer_interrupt, }; -static int __init gemini_timer_of_init(struct device_node *np) +static int __init fttmr010_timer_common_init(struct device_node *np) { - static struct regmap *map; int irq; - int ret; - u32 val; - - map = syscon_regmap_lookup_by_phandle(np, "syscon"); - if (IS_ERR(map)) { - pr_err("Can't get regmap for syscon handle"); - return -ENODEV; - } - ret = regmap_read(map, GLOBAL_STATUS, &val); - if (ret) { - pr_err("Can't read syscon status register"); - return -ENXIO; - } base = of_iomap(np, 0); if (!base) { @@ -219,26 +195,6 @@ static int __init gemini_timer_of_init(struct device_node *np) return -EINVAL; } - tick_rate = REG_TO_AHB_SPEED(val) * 1000000; - printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000); - - tick_rate /= 6; /* APB bus run AHB*(1/6) */ - - switch (val & CPU_AHB_RATIO_MASK) { - case CPU_AHB_1_1: - printk(KERN_CONT "(1/1)\n"); - break; - case CPU_AHB_3_2: - printk(KERN_CONT "(3/2)\n"); - break; - case CPU_AHB_24_13: - printk(KERN_CONT "(24/13)\n"); - break; - case CPU_AHB_2_1: - printk(KERN_CONT "(2/1)\n"); - break; - } - /* * Reset the interrupt mask and status */ @@ -273,4 +229,75 @@ static int __init gemini_timer_of_init(struct device_node *np) return 0; } + +static int __init fttmr010_timer_of_init(struct device_node *np) +{ + /* + * These implementations require a clock reference. + * FIXME: we currently only support clocking using PCLK + * and using EXTCLK is not supported in the driver. + */ + struct clk *clk; + + clk = of_clk_get_by_name(np, "PCLK"); + if (IS_ERR(clk)) { + pr_err("could not get PCLK"); + return PTR_ERR(clk); + } + tick_rate = clk_get_rate(clk); + + return fttmr010_timer_common_init(np); +} +CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_of_init); + +/* + * Gemini-specific: relevant registers in the global syscon + */ +#define GLOBAL_STATUS 0x04 +#define CPU_AHB_RATIO_MASK (0x3 << 18) +#define CPU_AHB_1_1 (0x0 << 18) +#define CPU_AHB_3_2 (0x1 << 18) +#define CPU_AHB_24_13 (0x2 << 18) +#define CPU_AHB_2_1 (0x3 << 18) +#define REG_TO_AHB_SPEED(reg) ((((reg) >> 15) & 0x7) * 10 + 130) + +static int __init gemini_timer_of_init(struct device_node *np) +{ + static struct regmap *map; + int ret; + u32 val; + + map = syscon_regmap_lookup_by_phandle(np, "syscon"); + if (IS_ERR(map)) { + pr_err("Can't get regmap for syscon handle\n"); + return -ENODEV; + } + ret = regmap_read(map, GLOBAL_STATUS, &val); + if (ret) { + pr_err("Can't read syscon status register\n"); + return -ENXIO; + } + + tick_rate = REG_TO_AHB_SPEED(val) * 1000000; + pr_info("Bus: %dMHz ", tick_rate / 1000000); + + tick_rate /= 6; /* APB bus run AHB*(1/6) */ + + switch (val & CPU_AHB_RATIO_MASK) { + case CPU_AHB_1_1: + pr_cont("(1/1)\n"); + break; + case CPU_AHB_3_2: + pr_cont("(3/2)\n"); + break; + case CPU_AHB_24_13: + pr_cont("(24/13)\n"); + break; + case CPU_AHB_2_1: + pr_cont("(2/1)\n"); + break; + } + + return fttmr010_timer_common_init(np); +} CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", gemini_timer_of_init); |