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