aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/common/timer-sp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/common/timer-sp.c')
-rw-r--r--arch/arm/common/timer-sp.c82
1 files changed, 51 insertions, 31 deletions
diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c
index 6ef3342153b9..41df47875122 100644
--- a/arch/arm/common/timer-sp.c
+++ b/arch/arm/common/timer-sp.c
@@ -18,53 +18,67 @@
18 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21#include <linux/clk.h>
21#include <linux/clocksource.h> 22#include <linux/clocksource.h>
22#include <linux/clockchips.h> 23#include <linux/clockchips.h>
24#include <linux/err.h>
23#include <linux/interrupt.h> 25#include <linux/interrupt.h>
24#include <linux/irq.h> 26#include <linux/irq.h>
25#include <linux/io.h> 27#include <linux/io.h>
26 28
27#include <asm/hardware/arm_timer.h> 29#include <asm/hardware/arm_timer.h>
28 30
29/* 31static long __init sp804_get_clock_rate(const char *name)
30 * These timers are currently always setup to be clocked at 1MHz. 32{
31 */ 33 struct clk *clk;
32#define TIMER_FREQ_KHZ (1000) 34 long rate;
33#define TIMER_RELOAD (TIMER_FREQ_KHZ * 1000 / HZ) 35 int err;
36
37 clk = clk_get_sys("sp804", name);
38 if (IS_ERR(clk)) {
39 pr_err("sp804: %s clock not found: %d\n", name,
40 (int)PTR_ERR(clk));
41 return PTR_ERR(clk);
42 }
34 43
35static void __iomem *clksrc_base; 44 err = clk_enable(clk);
45 if (err) {
46 pr_err("sp804: %s clock failed to enable: %d\n", name, err);
47 clk_put(clk);
48 return err;
49 }
36 50
37static cycle_t sp804_read(struct clocksource *cs) 51 rate = clk_get_rate(clk);
38{ 52 if (rate < 0) {
39 return ~readl(clksrc_base + TIMER_VALUE); 53 pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate);
40} 54 clk_disable(clk);
55 clk_put(clk);
56 }
41 57
42static struct clocksource clocksource_sp804 = { 58 return rate;
43 .name = "timer3", 59}
44 .rating = 200,
45 .read = sp804_read,
46 .mask = CLOCKSOURCE_MASK(32),
47 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
48};
49 60
50void __init sp804_clocksource_init(void __iomem *base) 61void __init sp804_clocksource_init(void __iomem *base, const char *name)
51{ 62{
52 struct clocksource *cs = &clocksource_sp804; 63 long rate = sp804_get_clock_rate(name);
53 64
54 clksrc_base = base; 65 if (rate < 0)
66 return;
55 67
56 /* setup timer 0 as free-running clocksource */ 68 /* setup timer 0 as free-running clocksource */
57 writel(0, clksrc_base + TIMER_CTRL); 69 writel(0, base + TIMER_CTRL);
58 writel(0xffffffff, clksrc_base + TIMER_LOAD); 70 writel(0xffffffff, base + TIMER_LOAD);
59 writel(0xffffffff, clksrc_base + TIMER_VALUE); 71 writel(0xffffffff, base + TIMER_VALUE);
60 writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, 72 writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
61 clksrc_base + TIMER_CTRL); 73 base + TIMER_CTRL);
62 74
63 clocksource_register_khz(cs, TIMER_FREQ_KHZ); 75 clocksource_mmio_init(base + TIMER_VALUE, name,
76 rate, 200, 32, clocksource_mmio_readl_down);
64} 77}
65 78
66 79
67static void __iomem *clkevt_base; 80static void __iomem *clkevt_base;
81static unsigned long clkevt_reload;
68 82
69/* 83/*
70 * IRQ handler for the timer 84 * IRQ handler for the timer
@@ -90,7 +104,7 @@ static void sp804_set_mode(enum clock_event_mode mode,
90 104
91 switch (mode) { 105 switch (mode) {
92 case CLOCK_EVT_MODE_PERIODIC: 106 case CLOCK_EVT_MODE_PERIODIC:
93 writel(TIMER_RELOAD, clkevt_base + TIMER_LOAD); 107 writel(clkevt_reload, clkevt_base + TIMER_LOAD);
94 ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; 108 ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
95 break; 109 break;
96 110
@@ -120,7 +134,6 @@ static int sp804_set_next_event(unsigned long next,
120} 134}
121 135
122static struct clock_event_device sp804_clockevent = { 136static struct clock_event_device sp804_clockevent = {
123 .name = "timer0",
124 .shift = 32, 137 .shift = 32,
125 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 138 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
126 .set_mode = sp804_set_mode, 139 .set_mode = sp804_set_mode,
@@ -136,17 +149,24 @@ static struct irqaction sp804_timer_irq = {
136 .dev_id = &sp804_clockevent, 149 .dev_id = &sp804_clockevent,
137}; 150};
138 151
139void __init sp804_clockevents_init(void __iomem *base, unsigned int timer_irq) 152void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
153 const char *name)
140{ 154{
141 struct clock_event_device *evt = &sp804_clockevent; 155 struct clock_event_device *evt = &sp804_clockevent;
156 long rate = sp804_get_clock_rate(name);
157
158 if (rate < 0)
159 return;
142 160
143 clkevt_base = base; 161 clkevt_base = base;
162 clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ);
144 163
145 evt->irq = timer_irq; 164 evt->name = name;
146 evt->mult = div_sc(TIMER_FREQ_KHZ, NSEC_PER_MSEC, evt->shift); 165 evt->irq = irq;
166 evt->mult = div_sc(rate, NSEC_PER_SEC, evt->shift);
147 evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt); 167 evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt);
148 evt->min_delta_ns = clockevent_delta2ns(0xf, evt); 168 evt->min_delta_ns = clockevent_delta2ns(0xf, evt);
149 169
150 setup_irq(timer_irq, &sp804_timer_irq); 170 setup_irq(irq, &sp804_timer_irq);
151 clockevents_register_device(evt); 171 clockevents_register_device(evt);
152} 172}