diff options
Diffstat (limited to 'drivers/clocksource/timer-stm32.c')
-rw-r--r-- | drivers/clocksource/timer-stm32.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c index 0d37f1a1994e..21b7492c963a 100644 --- a/drivers/clocksource/timer-stm32.c +++ b/drivers/clocksource/timer-stm32.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/of_irq.h> | 16 | #include <linux/of_irq.h> |
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/reset.h> | 18 | #include <linux/reset.h> |
19 | #include <linux/sched_clock.h> | ||
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | 21 | ||
21 | #include "timer-of.h" | 22 | #include "timer-of.h" |
@@ -80,6 +81,13 @@ static int stm32_timer_of_bits_get(struct timer_of *to) | |||
80 | return pd->bits; | 81 | return pd->bits; |
81 | } | 82 | } |
82 | 83 | ||
84 | static void __iomem *stm32_timer_cnt __read_mostly; | ||
85 | |||
86 | static u64 notrace stm32_read_sched_clock(void) | ||
87 | { | ||
88 | return readl_relaxed(stm32_timer_cnt); | ||
89 | } | ||
90 | |||
83 | static void stm32_clock_event_disable(struct timer_of *to) | 91 | static void stm32_clock_event_disable(struct timer_of *to) |
84 | { | 92 | { |
85 | writel_relaxed(0, timer_of_base(to) + TIM_DIER); | 93 | writel_relaxed(0, timer_of_base(to) + TIM_DIER); |
@@ -204,6 +212,31 @@ static void __init stm32_timer_set_prescaler(struct timer_of *to) | |||
204 | to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ); | 212 | to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ); |
205 | } | 213 | } |
206 | 214 | ||
215 | static int __init stm32_clocksource_init(struct timer_of *to) | ||
216 | { | ||
217 | u32 bits = stm32_timer_of_bits_get(to); | ||
218 | const char *name = to->np->full_name; | ||
219 | |||
220 | /* | ||
221 | * This driver allows to register several timers and relies on | ||
222 | * the generic time framework to select the right one. | ||
223 | * However, nothing allows to do the same for the | ||
224 | * sched_clock. We are not interested in a sched_clock for the | ||
225 | * 16-bit timers but only for the 32-bit one, so if no 32-bit | ||
226 | * timer is registered yet, we select this 32-bit timer as a | ||
227 | * sched_clock. | ||
228 | */ | ||
229 | if (bits == 32 && !stm32_timer_cnt) { | ||
230 | stm32_timer_cnt = timer_of_base(to) + TIM_CNT; | ||
231 | sched_clock_register(stm32_read_sched_clock, bits, timer_of_rate(to)); | ||
232 | pr_info("%s: STM32 sched_clock registered\n", name); | ||
233 | } | ||
234 | |||
235 | return clocksource_mmio_init(timer_of_base(to) + TIM_CNT, name, | ||
236 | timer_of_rate(to), bits == 32 ? 250 : 100, | ||
237 | bits, clocksource_mmio_readl_up); | ||
238 | } | ||
239 | |||
207 | static void __init stm32_clockevent_init(struct timer_of *to) | 240 | static void __init stm32_clockevent_init(struct timer_of *to) |
208 | { | 241 | { |
209 | u32 bits = stm32_timer_of_bits_get(to); | 242 | u32 bits = stm32_timer_of_bits_get(to); |
@@ -256,6 +289,10 @@ static int __init stm32_timer_init(struct device_node *node) | |||
256 | 289 | ||
257 | stm32_timer_set_prescaler(to); | 290 | stm32_timer_set_prescaler(to); |
258 | 291 | ||
292 | ret = stm32_clocksource_init(to); | ||
293 | if (ret) | ||
294 | goto deinit; | ||
295 | |||
259 | stm32_clockevent_init(to); | 296 | stm32_clockevent_init(to); |
260 | return 0; | 297 | return 0; |
261 | 298 | ||