Commit 28e71e2f authored by Linus Walleij's avatar Linus Walleij Committed by Daniel Lezcano
Browse files

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: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarDaniel Lezcano <daniel.lezcano@linaro.org>
parent f5bf0ee4
Loading
Loading
Loading
Loading
+73 −46
Original line number Diff line number Diff line
@@ -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);