aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/timer-stm32.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource/timer-stm32.c')
-rw-r--r--drivers/clocksource/timer-stm32.c56
1 files changed, 44 insertions, 12 deletions
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 928ac281f937..882037f1d8d6 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -24,14 +24,18 @@
24#define TIM_DIER 0x0c 24#define TIM_DIER 0x0c
25#define TIM_SR 0x10 25#define TIM_SR 0x10
26#define TIM_EGR 0x14 26#define TIM_EGR 0x14
27#define TIM_CNT 0x24
27#define TIM_PSC 0x28 28#define TIM_PSC 0x28
28#define TIM_ARR 0x2c 29#define TIM_ARR 0x2c
30#define TIM_CCR1 0x34
29 31
30#define TIM_CR1_CEN BIT(0) 32#define TIM_CR1_CEN BIT(0)
33#define TIM_CR1_UDIS BIT(1)
31#define TIM_CR1_OPM BIT(3) 34#define TIM_CR1_OPM BIT(3)
32#define TIM_CR1_ARPE BIT(7) 35#define TIM_CR1_ARPE BIT(7)
33 36
34#define TIM_DIER_UIE BIT(0) 37#define TIM_DIER_UIE BIT(0)
38#define TIM_DIER_CC1IE BIT(1)
35 39
36#define TIM_SR_UIF BIT(0) 40#define TIM_SR_UIF BIT(0)
37 41
@@ -40,33 +44,57 @@
40#define TIM_PSC_MAX USHRT_MAX 44#define TIM_PSC_MAX USHRT_MAX
41#define TIM_PSC_CLKRATE 10000 45#define TIM_PSC_CLKRATE 10000
42 46
47static void stm32_clock_event_disable(struct timer_of *to)
48{
49 writel_relaxed(0, timer_of_base(to) + TIM_DIER);
50}
51
52static void stm32_clock_event_enable(struct timer_of *to)
53{
54 writel_relaxed(TIM_CR1_UDIS | TIM_CR1_CEN, timer_of_base(to) + TIM_CR1);
55}
56
43static int stm32_clock_event_shutdown(struct clock_event_device *clkevt) 57static int stm32_clock_event_shutdown(struct clock_event_device *clkevt)
44{ 58{
45 struct timer_of *to = to_timer_of(clkevt); 59 struct timer_of *to = to_timer_of(clkevt);
46 60
47 writel_relaxed(0, timer_of_base(to) + TIM_CR1); 61 stm32_clock_event_disable(to);
48 62
49 return 0; 63 return 0;
50} 64}
51 65
52static int stm32_clock_event_set_periodic(struct clock_event_device *clkevt) 66static int stm32_clock_event_set_next_event(unsigned long evt,
67 struct clock_event_device *clkevt)
53{ 68{
54 struct timer_of *to = to_timer_of(clkevt); 69 struct timer_of *to = to_timer_of(clkevt);
70 unsigned long now, next;
71
72 next = readl_relaxed(timer_of_base(to) + TIM_CNT) + evt;
73 writel_relaxed(next, timer_of_base(to) + TIM_CCR1);
74 now = readl_relaxed(timer_of_base(to) + TIM_CNT);
75
76 if ((next - now) > evt)
77 return -ETIME;
55 78
56 writel_relaxed(timer_of_period(to), timer_of_base(to) + TIM_ARR); 79 writel_relaxed(TIM_DIER_CC1IE, timer_of_base(to) + TIM_DIER);
57 writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, timer_of_base(to) + TIM_CR1);
58 80
59 return 0; 81 return 0;
60} 82}
61 83
62static int stm32_clock_event_set_next_event(unsigned long evt, 84static int stm32_clock_event_set_periodic(struct clock_event_device *clkevt)
63 struct clock_event_device *clkevt) 85{
86 struct timer_of *to = to_timer_of(clkevt);
87
88 stm32_clock_event_enable(to);
89
90 return stm32_clock_event_set_next_event(timer_of_period(to), clkevt);
91}
92
93static int stm32_clock_event_set_oneshot(struct clock_event_device *clkevt)
64{ 94{
65 struct timer_of *to = to_timer_of(clkevt); 95 struct timer_of *to = to_timer_of(clkevt);
66 96
67 writel_relaxed(evt, timer_of_base(to) + TIM_ARR); 97 stm32_clock_event_enable(to);
68 writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
69 timer_of_base(to) + TIM_CR1);
70 98
71 return 0; 99 return 0;
72} 100}
@@ -78,6 +106,11 @@ static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
78 106
79 writel_relaxed(0, timer_of_base(to) + TIM_SR); 107 writel_relaxed(0, timer_of_base(to) + TIM_SR);
80 108
109 if (clockevent_state_periodic(clkevt))
110 stm32_clock_event_set_periodic(clkevt);
111 else
112 stm32_clock_event_shutdown(clkevt);
113
81 clkevt->event_handler(clkevt); 114 clkevt->event_handler(clkevt);
82 115
83 return IRQ_HANDLED; 116 return IRQ_HANDLED;
@@ -108,9 +141,10 @@ static void __init stm32_clockevent_init(struct timer_of *to)
108 141
109 to->clkevt.name = to->np->full_name; 142 to->clkevt.name = to->np->full_name;
110 to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC; 143 to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
144 to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
111 to->clkevt.set_state_shutdown = stm32_clock_event_shutdown; 145 to->clkevt.set_state_shutdown = stm32_clock_event_shutdown;
112 to->clkevt.set_state_periodic = stm32_clock_event_set_periodic; 146 to->clkevt.set_state_periodic = stm32_clock_event_set_periodic;
113 to->clkevt.set_state_oneshot = stm32_clock_event_shutdown; 147 to->clkevt.set_state_oneshot = stm32_clock_event_set_oneshot;
114 to->clkevt.tick_resume = stm32_clock_event_shutdown; 148 to->clkevt.tick_resume = stm32_clock_event_shutdown;
115 to->clkevt.set_next_event = stm32_clock_event_set_next_event; 149 to->clkevt.set_next_event = stm32_clock_event_set_next_event;
116 150
@@ -129,12 +163,10 @@ static void __init stm32_clockevent_init(struct timer_of *to)
129 prescaler = prescaler < TIM_PSC_MAX ? prescaler : TIM_PSC_MAX; 163 prescaler = prescaler < TIM_PSC_MAX ? prescaler : TIM_PSC_MAX;
130 to->clkevt.rating = 100; 164 to->clkevt.rating = 100;
131 } 165 }
132 writel_relaxed(0, timer_of_base(to) + TIM_ARR);
133 166
134 writel_relaxed(prescaler - 1, timer_of_base(to) + TIM_PSC); 167 writel_relaxed(prescaler - 1, timer_of_base(to) + TIM_PSC);
135 writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR); 168 writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR);
136 writel_relaxed(0, timer_of_base(to) + TIM_SR); 169 writel_relaxed(0, timer_of_base(to) + TIM_SR);
137 writel_relaxed(TIM_DIER_UIE, timer_of_base(to) + TIM_DIER);
138 170
139 /* Adjust rate and period given the prescaler value */ 171 /* Adjust rate and period given the prescaler value */
140 to->of_clk.rate = DIV_ROUND_CLOSEST(to->of_clk.rate, prescaler); 172 to->of_clk.rate = DIV_ROUND_CLOSEST(to->of_clk.rate, prescaler);