clocksource/drivers/fttmr010: Refactor to handle clock
authorLinus Walleij <linus.walleij@linaro.org>
Fri, 24 Mar 2017 21:32:35 +0000 (22:32 +0100)
committerDaniel Lezcano <daniel.lezcano@linaro.org>
Fri, 7 Apr 2017 14:23:08 +0000 (16:23 +0200)
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>
drivers/clocksource/timer-fttmr010.c

index e37ec3d..b4a6f1e 100644 (file)
 #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);