diff options
author | Colin Cross <ccross@android.com> | 2010-11-28 19:26:19 -0500 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2011-02-10 01:17:38 -0500 |
commit | 093617851c5fa0d1fdf5ce378f20691b7adb35e4 (patch) | |
tree | 293fb17e41c96168bb5f2c7661fbcf81d7c3f00a /arch/arm/mach-tegra/timer.c | |
parent | 3c3895b4bf58d709ad4709480ceb2bb006741972 (diff) |
ARM: tegra: timer: Add idle and suspend support to timers
Implement read_persistent_clock by reading the Tegra RTC
registers that stay running during suspend.
Save and restore the timer configuration register in
suspend.
Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'arch/arm/mach-tegra/timer.c')
-rw-r--r-- | arch/arm/mach-tegra/timer.c | 60 |
1 files changed, 58 insertions, 2 deletions
diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c index 36b53a7294c1..ffa6a6859746 100644 --- a/arch/arm/mach-tegra/timer.c +++ b/arch/arm/mach-tegra/timer.c | |||
@@ -38,6 +38,10 @@ | |||
38 | #include "board.h" | 38 | #include "board.h" |
39 | #include "clock.h" | 39 | #include "clock.h" |
40 | 40 | ||
41 | #define RTC_SECONDS 0x08 | ||
42 | #define RTC_SHADOW_SECONDS 0x0c | ||
43 | #define RTC_MILLISECONDS 0x10 | ||
44 | |||
41 | #define TIMERUS_CNTR_1US 0x10 | 45 | #define TIMERUS_CNTR_1US 0x10 |
42 | #define TIMERUS_USEC_CFG 0x14 | 46 | #define TIMERUS_USEC_CFG 0x14 |
43 | #define TIMERUS_CNTR_FREEZE 0x4c | 47 | #define TIMERUS_CNTR_FREEZE 0x4c |
@@ -50,9 +54,11 @@ | |||
50 | #define TIMER_PTV 0x0 | 54 | #define TIMER_PTV 0x0 |
51 | #define TIMER_PCR 0x4 | 55 | #define TIMER_PCR 0x4 |
52 | 56 | ||
53 | struct tegra_timer; | ||
54 | |||
55 | static void __iomem *timer_reg_base = IO_ADDRESS(TEGRA_TMR1_BASE); | 57 | static void __iomem *timer_reg_base = IO_ADDRESS(TEGRA_TMR1_BASE); |
58 | static void __iomem *rtc_base = IO_ADDRESS(TEGRA_RTC_BASE); | ||
59 | |||
60 | static struct timespec persistent_ts; | ||
61 | static u64 persistent_ms, last_persistent_ms; | ||
56 | 62 | ||
57 | #define timer_writel(value, reg) \ | 63 | #define timer_writel(value, reg) \ |
58 | __raw_writel(value, (u32)timer_reg_base + (reg)) | 64 | __raw_writel(value, (u32)timer_reg_base + (reg)) |
@@ -133,6 +139,42 @@ static void notrace tegra_update_sched_clock(void) | |||
133 | update_sched_clock(&cd, cyc, (u32)~0); | 139 | update_sched_clock(&cd, cyc, (u32)~0); |
134 | } | 140 | } |
135 | 141 | ||
142 | /* | ||
143 | * tegra_rtc_read - Reads the Tegra RTC registers | ||
144 | * Care must be taken that this funciton is not called while the | ||
145 | * tegra_rtc driver could be executing to avoid race conditions | ||
146 | * on the RTC shadow register | ||
147 | */ | ||
148 | u64 tegra_rtc_read_ms(void) | ||
149 | { | ||
150 | u32 ms = readl(rtc_base + RTC_MILLISECONDS); | ||
151 | u32 s = readl(rtc_base + RTC_SHADOW_SECONDS); | ||
152 | return (u64)s * MSEC_PER_SEC + ms; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * read_persistent_clock - Return time from a persistent clock. | ||
157 | * | ||
158 | * Reads the time from a source which isn't disabled during PM, the | ||
159 | * 32k sync timer. Convert the cycles elapsed since last read into | ||
160 | * nsecs and adds to a monotonically increasing timespec. | ||
161 | * Care must be taken that this funciton is not called while the | ||
162 | * tegra_rtc driver could be executing to avoid race conditions | ||
163 | * on the RTC shadow register | ||
164 | */ | ||
165 | void read_persistent_clock(struct timespec *ts) | ||
166 | { | ||
167 | u64 delta; | ||
168 | struct timespec *tsp = &persistent_ts; | ||
169 | |||
170 | last_persistent_ms = persistent_ms; | ||
171 | persistent_ms = tegra_rtc_read_ms(); | ||
172 | delta = persistent_ms - last_persistent_ms; | ||
173 | |||
174 | timespec_add_ns(tsp, delta * NSEC_PER_MSEC); | ||
175 | *ts = *tsp; | ||
176 | } | ||
177 | |||
136 | static irqreturn_t tegra_timer_interrupt(int irq, void *dev_id) | 178 | static irqreturn_t tegra_timer_interrupt(int irq, void *dev_id) |
137 | { | 179 | { |
138 | struct clock_event_device *evt = (struct clock_event_device *)dev_id; | 180 | struct clock_event_device *evt = (struct clock_event_device *)dev_id; |
@@ -204,3 +246,17 @@ static void __init tegra_init_timer(void) | |||
204 | struct sys_timer tegra_timer = { | 246 | struct sys_timer tegra_timer = { |
205 | .init = tegra_init_timer, | 247 | .init = tegra_init_timer, |
206 | }; | 248 | }; |
249 | |||
250 | #ifdef CONFIG_PM | ||
251 | static u32 usec_config; | ||
252 | |||
253 | void tegra_timer_suspend(void) | ||
254 | { | ||
255 | usec_config = timer_readl(TIMERUS_USEC_CFG); | ||
256 | } | ||
257 | |||
258 | void tegra_timer_resume(void) | ||
259 | { | ||
260 | timer_writel(usec_config, TIMERUS_USEC_CFG); | ||
261 | } | ||
262 | #endif | ||