Commit | Line | Data |
---|---|---|
aa218daf PW |
1 | /* |
2 | * OMAP 32ksynctimer/counter_32k-related code | |
3 | * | |
4 | * Copyright (C) 2009 Texas Instruments | |
5 | * Copyright (C) 2010 Nokia Corporation | |
6 | * Tony Lindgren <tony@atomide.com> | |
7 | * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License version 2 as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * NOTE: This timer is not the same timer as the old OMAP1 MPU timer. | |
14 | */ | |
15 | #include <linux/kernel.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/clk.h> | |
18 | #include <linux/io.h> | |
19 | ||
20 | #include <plat/common.h> | |
21 | #include <plat/board.h> | |
22 | ||
23 | #include <plat/clock.h> | |
24 | ||
25 | ||
26 | /* | |
27 | * 32KHz clocksource ... always available, on pretty most chips except | |
28 | * OMAP 730 and 1510. Other timers could be used as clocksources, with | |
29 | * higher resolution in free-running counter modes (e.g. 12 MHz xtal), | |
30 | * but systems won't necessarily want to spend resources that way. | |
31 | */ | |
32 | ||
33 | #define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410 | |
34 | ||
35 | #if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) | |
36 | ||
37 | #include <linux/clocksource.h> | |
38 | ||
39 | /* | |
40 | * offset_32k holds the init time counter value. It is then subtracted | |
41 | * from every counter read to achieve a counter that counts time from the | |
42 | * kernel boot (needed for sched_clock()). | |
43 | */ | |
44 | static u32 offset_32k __read_mostly; | |
45 | ||
46 | #ifdef CONFIG_ARCH_OMAP16XX | |
47 | static cycle_t omap16xx_32k_read(struct clocksource *cs) | |
48 | { | |
49 | return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k; | |
50 | } | |
51 | #else | |
52 | #define omap16xx_32k_read NULL | |
53 | #endif | |
54 | ||
55 | #ifdef CONFIG_ARCH_OMAP2420 | |
56 | static cycle_t omap2420_32k_read(struct clocksource *cs) | |
57 | { | |
58 | return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k; | |
59 | } | |
60 | #else | |
61 | #define omap2420_32k_read NULL | |
62 | #endif | |
63 | ||
64 | #ifdef CONFIG_ARCH_OMAP2430 | |
65 | static cycle_t omap2430_32k_read(struct clocksource *cs) | |
66 | { | |
67 | return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k; | |
68 | } | |
69 | #else | |
70 | #define omap2430_32k_read NULL | |
71 | #endif | |
72 | ||
73 | #ifdef CONFIG_ARCH_OMAP3 | |
74 | static cycle_t omap34xx_32k_read(struct clocksource *cs) | |
75 | { | |
76 | return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k; | |
77 | } | |
78 | #else | |
79 | #define omap34xx_32k_read NULL | |
80 | #endif | |
81 | ||
82 | #ifdef CONFIG_ARCH_OMAP4 | |
83 | static cycle_t omap44xx_32k_read(struct clocksource *cs) | |
84 | { | |
85 | return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k; | |
86 | } | |
87 | #else | |
88 | #define omap44xx_32k_read NULL | |
89 | #endif | |
90 | ||
91 | /* | |
92 | * Kernel assumes that sched_clock can be called early but may not have | |
93 | * things ready yet. | |
94 | */ | |
95 | static cycle_t omap_32k_read_dummy(struct clocksource *cs) | |
96 | { | |
97 | return 0; | |
98 | } | |
99 | ||
100 | static struct clocksource clocksource_32k = { | |
101 | .name = "32k_counter", | |
102 | .rating = 250, | |
103 | .read = omap_32k_read_dummy, | |
104 | .mask = CLOCKSOURCE_MASK(32), | |
aa218daf PW |
105 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
106 | }; | |
107 | ||
108 | /* | |
109 | * Returns current time from boot in nsecs. It's OK for this to wrap | |
110 | * around for now, as it's just a relative time stamp. | |
111 | */ | |
112 | unsigned long long sched_clock(void) | |
113 | { | |
114 | return clocksource_cyc2ns(clocksource_32k.read(&clocksource_32k), | |
115 | clocksource_32k.mult, clocksource_32k.shift); | |
116 | } | |
117 | ||
118 | /** | |
119 | * read_persistent_clock - Return time from a persistent clock. | |
120 | * | |
121 | * Reads the time from a source which isn't disabled during PM, the | |
122 | * 32k sync timer. Convert the cycles elapsed since last read into | |
123 | * nsecs and adds to a monotonically increasing timespec. | |
124 | */ | |
125 | static struct timespec persistent_ts; | |
126 | static cycles_t cycles, last_cycles; | |
127 | void read_persistent_clock(struct timespec *ts) | |
128 | { | |
129 | unsigned long long nsecs; | |
130 | cycles_t delta; | |
131 | struct timespec *tsp = &persistent_ts; | |
132 | ||
133 | last_cycles = cycles; | |
134 | cycles = clocksource_32k.read(&clocksource_32k); | |
135 | delta = cycles - last_cycles; | |
136 | ||
137 | nsecs = clocksource_cyc2ns(delta, | |
138 | clocksource_32k.mult, clocksource_32k.shift); | |
139 | ||
140 | timespec_add_ns(tsp, nsecs); | |
141 | *ts = *tsp; | |
142 | } | |
143 | ||
144 | static int __init omap_init_clocksource_32k(void) | |
145 | { | |
146 | static char err[] __initdata = KERN_ERR | |
147 | "%s: can't register clocksource!\n"; | |
148 | ||
149 | if (cpu_is_omap16xx() || cpu_class_is_omap2()) { | |
150 | struct clk *sync_32k_ick; | |
151 | ||
152 | if (cpu_is_omap16xx()) | |
153 | clocksource_32k.read = omap16xx_32k_read; | |
154 | else if (cpu_is_omap2420()) | |
155 | clocksource_32k.read = omap2420_32k_read; | |
156 | else if (cpu_is_omap2430()) | |
157 | clocksource_32k.read = omap2430_32k_read; | |
158 | else if (cpu_is_omap34xx()) | |
159 | clocksource_32k.read = omap34xx_32k_read; | |
160 | else if (cpu_is_omap44xx()) | |
161 | clocksource_32k.read = omap44xx_32k_read; | |
162 | else | |
163 | return -ENODEV; | |
164 | ||
165 | sync_32k_ick = clk_get(NULL, "omap_32ksync_ick"); | |
166 | if (sync_32k_ick) | |
167 | clk_enable(sync_32k_ick); | |
168 | ||
aa218daf PW |
169 | offset_32k = clocksource_32k.read(&clocksource_32k); |
170 | ||
8437c25e | 171 | if (clocksource_register_hz(&clocksource_32k, 32768)) |
aa218daf PW |
172 | printk(err, clocksource_32k.name); |
173 | } | |
174 | return 0; | |
175 | } | |
176 | arch_initcall(omap_init_clocksource_32k); | |
177 | ||
178 | #endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */ | |
179 |