1 /* linux/arch/arm/mach-msm/timer.c
3 * Copyright (C) 2007 Google, Inc.
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <linux/init.h>
17 #include <linux/time.h>
18 #include <linux/interrupt.h>
19 #include <linux/irq.h>
20 #include <linux/clk.h>
21 #include <linux/clockchips.h>
22 #include <linux/delay.h>
25 #include <asm/mach/time.h>
26 #include <mach/msm_iomap.h>
29 #define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
31 #define MSM_DGT_SHIFT (5)
33 #define TIMER_MATCH_VAL 0x0000
34 #define TIMER_COUNT_VAL 0x0004
35 #define TIMER_ENABLE 0x0008
36 #define TIMER_ENABLE_CLR_ON_MATCH_EN 2
37 #define TIMER_ENABLE_EN 1
38 #define TIMER_CLEAR 0x000C
40 #define CSR_PROTECTION 0x0020
41 #define CSR_PROTECTION_EN 1
44 #define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
47 struct clock_event_device clockevent
;
48 struct clocksource clocksource
;
50 void __iomem
*regbase
;
55 static irqreturn_t
msm_timer_interrupt(int irq
, void *dev_id
)
57 struct clock_event_device
*evt
= dev_id
;
58 evt
->event_handler(evt
);
62 static cycle_t
msm_gpt_read(struct clocksource
*cs
)
64 return readl(MSM_GPT_BASE
+ TIMER_COUNT_VAL
);
67 static cycle_t
msm_dgt_read(struct clocksource
*cs
)
69 return readl(MSM_DGT_BASE
+ TIMER_COUNT_VAL
) >> MSM_DGT_SHIFT
;
72 static int msm_timer_set_next_event(unsigned long cycles
,
73 struct clock_event_device
*evt
)
75 struct msm_clock
*clock
= container_of(evt
, struct msm_clock
, clockevent
);
76 uint32_t now
= readl(clock
->regbase
+ TIMER_COUNT_VAL
);
77 uint32_t alarm
= now
+ (cycles
<< clock
->shift
);
80 writel(alarm
, clock
->regbase
+ TIMER_MATCH_VAL
);
81 now
= readl(clock
->regbase
+ TIMER_COUNT_VAL
);
83 if (late
>= (-2 << clock
->shift
) && late
< DGT_HZ
*5) {
84 printk(KERN_NOTICE
"msm_timer_set_next_event(%lu) clock %s, "
85 "alarm already expired, now %x, alarm %x, late %d\n",
86 cycles
, clock
->clockevent
.name
, now
, alarm
, late
);
92 static void msm_timer_set_mode(enum clock_event_mode mode
,
93 struct clock_event_device
*evt
)
95 struct msm_clock
*clock
= container_of(evt
, struct msm_clock
, clockevent
);
97 case CLOCK_EVT_MODE_RESUME
:
98 case CLOCK_EVT_MODE_PERIODIC
:
100 case CLOCK_EVT_MODE_ONESHOT
:
101 writel(TIMER_ENABLE_EN
, clock
->regbase
+ TIMER_ENABLE
);
103 case CLOCK_EVT_MODE_UNUSED
:
104 case CLOCK_EVT_MODE_SHUTDOWN
:
105 writel(0, clock
->regbase
+ TIMER_ENABLE
);
110 static struct msm_clock msm_clocks
[] = {
114 .features
= CLOCK_EVT_FEAT_ONESHOT
,
117 .set_next_event
= msm_timer_set_next_event
,
118 .set_mode
= msm_timer_set_mode
,
123 .read
= msm_gpt_read
,
124 .mask
= CLOCKSOURCE_MASK(32),
126 .flags
= CLOCK_SOURCE_IS_CONTINUOUS
,
130 .flags
= IRQF_DISABLED
| IRQF_TIMER
| IRQF_TRIGGER_RISING
,
131 .handler
= msm_timer_interrupt
,
132 .dev_id
= &msm_clocks
[0].clockevent
,
133 .irq
= INT_GP_TIMER_EXP
135 .regbase
= MSM_GPT_BASE
,
141 .features
= CLOCK_EVT_FEAT_ONESHOT
,
142 .shift
= 32 + MSM_DGT_SHIFT
,
144 .set_next_event
= msm_timer_set_next_event
,
145 .set_mode
= msm_timer_set_mode
,
150 .read
= msm_dgt_read
,
151 .mask
= CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT
)),
152 .shift
= 24 - MSM_DGT_SHIFT
,
153 .flags
= CLOCK_SOURCE_IS_CONTINUOUS
,
157 .flags
= IRQF_DISABLED
| IRQF_TIMER
| IRQF_TRIGGER_RISING
,
158 .handler
= msm_timer_interrupt
,
159 .dev_id
= &msm_clocks
[1].clockevent
,
160 .irq
= INT_DEBUG_TIMER_EXP
162 .regbase
= MSM_DGT_BASE
,
163 .freq
= DGT_HZ
>> MSM_DGT_SHIFT
,
164 .shift
= MSM_DGT_SHIFT
168 static void __init
msm_timer_init(void)
173 for (i
= 0; i
< ARRAY_SIZE(msm_clocks
); i
++) {
174 struct msm_clock
*clock
= &msm_clocks
[i
];
175 struct clock_event_device
*ce
= &clock
->clockevent
;
176 struct clocksource
*cs
= &clock
->clocksource
;
177 writel(0, clock
->regbase
+ TIMER_ENABLE
);
178 writel(0, clock
->regbase
+ TIMER_CLEAR
);
179 writel(~0, clock
->regbase
+ TIMER_MATCH_VAL
);
181 ce
->mult
= div_sc(clock
->freq
, NSEC_PER_SEC
, ce
->shift
);
182 /* allow at least 10 seconds to notice that the timer wrapped */
184 clockevent_delta2ns(0xf0000000 >> clock
->shift
, ce
);
185 /* 4 gets rounded down to 3 */
186 ce
->min_delta_ns
= clockevent_delta2ns(4, ce
);
187 ce
->cpumask
= cpumask_of(0);
189 cs
->mult
= clocksource_hz2mult(clock
->freq
, cs
->shift
);
190 res
= clocksource_register(cs
);
192 printk(KERN_ERR
"msm_timer_init: clocksource_register "
193 "failed for %s\n", cs
->name
);
195 res
= setup_irq(clock
->irq
.irq
, &clock
->irq
);
197 printk(KERN_ERR
"msm_timer_init: setup_irq "
198 "failed for %s\n", cs
->name
);
200 clockevents_register_device(ce
);
204 struct sys_timer msm_timer
= {
205 .init
= msm_timer_init