~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to arch/arm/common/timer-sp.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 * along with this program; if not, write to the Free Software
19
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
20
 */
 
21
#include <linux/clk.h>
21
22
#include <linux/clocksource.h>
22
23
#include <linux/clockchips.h>
 
24
#include <linux/err.h>
23
25
#include <linux/interrupt.h>
24
26
#include <linux/irq.h>
25
27
#include <linux/io.h>
26
28
 
27
29
#include <asm/hardware/arm_timer.h>
28
30
 
29
 
/*
30
 
 * These timers are currently always setup to be clocked at 1MHz.
31
 
 */
32
 
#define TIMER_FREQ_KHZ  (1000)
33
 
#define TIMER_RELOAD    (TIMER_FREQ_KHZ * 1000 / HZ)
34
 
 
35
 
static void __iomem *clksrc_base;
36
 
 
37
 
static cycle_t sp804_read(struct clocksource *cs)
 
31
static long __init sp804_get_clock_rate(const char *name)
38
32
{
39
 
        return ~readl(clksrc_base + TIMER_VALUE);
 
33
        struct clk *clk;
 
34
        long rate;
 
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
        }
 
43
 
 
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
        }
 
50
 
 
51
        rate = clk_get_rate(clk);
 
52
        if (rate < 0) {
 
53
                pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate);
 
54
                clk_disable(clk);
 
55
                clk_put(clk);
 
56
        }
 
57
 
 
58
        return rate;
40
59
}
41
60
 
42
 
static struct clocksource clocksource_sp804 = {
43
 
        .name           = "timer3",
44
 
        .rating         = 200,
45
 
        .read           = sp804_read,
46
 
        .mask           = CLOCKSOURCE_MASK(32),
47
 
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
48
 
};
49
 
 
50
 
void __init sp804_clocksource_init(void __iomem *base)
 
61
void __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
68
        /* setup timer 0 as free-running clocksource */
57
 
        writel(0, clksrc_base + TIMER_CTRL);
58
 
        writel(0xffffffff, clksrc_base + TIMER_LOAD);
59
 
        writel(0xffffffff, clksrc_base + TIMER_VALUE);
 
69
        writel(0, base + TIMER_CTRL);
 
70
        writel(0xffffffff, base + TIMER_LOAD);
 
71
        writel(0xffffffff, base + TIMER_VALUE);
60
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
 
67
80
static void __iomem *clkevt_base;
 
81
static unsigned long clkevt_reload;
68
82
 
69
83
/*
70
84
 * IRQ handler for the timer
90
104
 
91
105
        switch (mode) {
92
106
        case CLOCK_EVT_MODE_PERIODIC:
93
 
                writel(TIMER_RELOAD, clkevt_base + TIMER_LOAD);
 
107
                writel(clkevt_reload, clkevt_base + TIMER_LOAD);
94
108
                ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
95
109
                break;
96
110
 
120
134
}
121
135
 
122
136
static struct clock_event_device sp804_clockevent = {
123
 
        .name           = "timer0",
124
137
        .shift          = 32,
125
138
        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
126
139
        .set_mode       = sp804_set_mode,
136
149
        .dev_id         = &sp804_clockevent,
137
150
};
138
151
 
139
 
void __init sp804_clockevents_init(void __iomem *base, unsigned int timer_irq)
 
152
void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
 
153
        const char *name)
140
154
{
141
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
161
        clkevt_base = base;
 
162
        clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ);
144
163
 
145
 
        evt->irq = timer_irq;
146
 
        evt->mult = div_sc(TIMER_FREQ_KHZ, NSEC_PER_MSEC, evt->shift);
 
164
        evt->name = name;
 
165
        evt->irq = irq;
 
166
        evt->mult = div_sc(rate, NSEC_PER_SEC, evt->shift);
147
167
        evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt);
148
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
171
        clockevents_register_device(evt);
152
172
}