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>
This commit is contained in:
committed by
Daniel Lezcano
parent
f5bf0ee4eb
commit
28e71e2fe8
@ -16,17 +16,7 @@
|
|||||||
#include <linux/clockchips.h>
|
#include <linux/clockchips.h>
|
||||||
#include <linux/clocksource.h>
|
#include <linux/clocksource.h>
|
||||||
#include <linux/sched_clock.h>
|
#include <linux/sched_clock.h>
|
||||||
|
#include <linux/clk.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)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register definitions for the timers
|
* Register definitions for the timers
|
||||||
@ -189,23 +179,9 @@ static struct irqaction fttmr010_timer_irq = {
|
|||||||
.handler = fttmr010_timer_interrupt,
|
.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 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);
|
base = of_iomap(np, 0);
|
||||||
if (!base) {
|
if (!base) {
|
||||||
@ -219,26 +195,6 @@ static int __init gemini_timer_of_init(struct device_node *np)
|
|||||||
return -EINVAL;
|
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
|
* Reset the interrupt mask and status
|
||||||
*/
|
*/
|
||||||
@ -273,4 +229,75 @@ static int __init gemini_timer_of_init(struct device_node *np)
|
|||||||
|
|
||||||
return 0;
|
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);
|
CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", gemini_timer_of_init);
|
||||||
|
Reference in New Issue
Block a user