summaryrefslogtreecommitdiff
path: root/drivers/clocksource/timer-sp804.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource/timer-sp804.c')
-rw-r--r--drivers/clocksource/timer-sp804.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c
index 401d592e85f5..e82a95ea4724 100644
--- a/drivers/clocksource/timer-sp804.c
+++ b/drivers/clocksource/timer-sp804.c
@@ -21,6 +21,10 @@
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
+#ifdef CONFIG_ARM
+#include <linux/delay.h>
+#endif
+
#include "timer-sp.h"
/* Hisilicon 64-bit timer(a variant of ARM SP804) */
@@ -102,6 +106,23 @@ static u64 notrace sp804_read(void)
return ~readl_relaxed(sched_clkevt->value);
}
+#ifdef CONFIG_ARM
+static struct delay_timer delay;
+static unsigned long sp804_read_delay_timer_read(void)
+{
+ return sp804_read();
+}
+
+static void sp804_register_delay_timer(int freq)
+{
+ delay.freq = freq;
+ delay.read_current_timer = sp804_read_delay_timer_read;
+ register_current_timer_delay(&delay);
+}
+#else
+static inline void sp804_register_delay_timer(int freq) {}
+#endif
+
static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
const char *name,
struct clk *clk,
@@ -114,6 +135,8 @@ static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
if (rate < 0)
return -EINVAL;
+ sp804_register_delay_timer(rate);
+
clkevt = sp804_clkevt_get(base);
writel(0, clkevt->ctrl);
@@ -155,14 +178,14 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static inline void timer_shutdown(struct clock_event_device *evt)
+static inline void evt_timer_shutdown(struct clock_event_device *evt)
{
writel(0, common_clkevt->ctrl);
}
static int sp804_shutdown(struct clock_event_device *evt)
{
- timer_shutdown(evt);
+ evt_timer_shutdown(evt);
return 0;
}
@@ -171,7 +194,7 @@ static int sp804_set_periodic(struct clock_event_device *evt)
unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
- timer_shutdown(evt);
+ evt_timer_shutdown(evt);
writel(common_clkevt->reload, common_clkevt->load);
writel(ctrl, common_clkevt->ctrl);
return 0;
@@ -259,6 +282,11 @@ static int __init sp804_of_init(struct device_node *np, struct sp804_timer *time
struct clk *clk1, *clk2;
const char *name = of_get_property(np, "compatible", NULL);
+ if (initialized) {
+ pr_debug("%pOF: skipping further SP804 timer device\n", np);
+ return 0;
+ }
+
base = of_iomap(np, 0);
if (!base)
return -ENXIO;
@@ -270,11 +298,6 @@ static int __init sp804_of_init(struct device_node *np, struct sp804_timer *time
writel(0, timer1_base + timer->ctrl);
writel(0, timer2_base + timer->ctrl);
- if (initialized || !of_device_is_available(np)) {
- ret = -EINVAL;
- goto err;
- }
-
clk1 = of_clk_get(np, 0);
if (IS_ERR(clk1))
clk1 = NULL;
@@ -318,6 +341,7 @@ static int __init sp804_of_init(struct device_node *np, struct sp804_timer *time
if (ret)
goto err;
}
+
initialized = true;
return 0;