[PATCH 3/3] clocksource: fttmr010: refactor to handle clock

From: Linus Walleij
Date: Fri Mar 24 2017 - 17:33:13 EST


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@xxxxxxxxxx>
---
drivers/clocksource/timer-fttmr010.c | 119 +++++++++++++++++++++--------------
1 file 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);
--
2.9.3