diff options
Diffstat (limited to 'drivers/clocksource/timer-stm32.c')
-rw-r--r-- | drivers/clocksource/timer-stm32.c | 107 |
1 files changed, 82 insertions, 25 deletions
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c index 882037f1d8d6..0d37f1a1994e 100644 --- a/drivers/clocksource/timer-stm32.c +++ b/drivers/clocksource/timer-stm32.c | |||
@@ -44,6 +44,42 @@ | |||
44 | #define TIM_PSC_MAX USHRT_MAX | 44 | #define TIM_PSC_MAX USHRT_MAX |
45 | #define TIM_PSC_CLKRATE 10000 | 45 | #define TIM_PSC_CLKRATE 10000 |
46 | 46 | ||
47 | struct stm32_timer_private { | ||
48 | int bits; | ||
49 | }; | ||
50 | |||
51 | /** | ||
52 | * stm32_timer_of_bits_set - set accessor helper | ||
53 | * @to: a timer_of structure pointer | ||
54 | * @bits: the number of bits (16 or 32) | ||
55 | * | ||
56 | * Accessor helper to set the number of bits in the timer-of private | ||
57 | * structure. | ||
58 | * | ||
59 | */ | ||
60 | static void stm32_timer_of_bits_set(struct timer_of *to, int bits) | ||
61 | { | ||
62 | struct stm32_timer_private *pd = to->private_data; | ||
63 | |||
64 | pd->bits = bits; | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * stm32_timer_of_bits_get - get accessor helper | ||
69 | * @to: a timer_of structure pointer | ||
70 | * | ||
71 | * Accessor helper to get the number of bits in the timer-of private | ||
72 | * structure. | ||
73 | * | ||
74 | * Returns an integer corresponding to the number of bits. | ||
75 | */ | ||
76 | static int stm32_timer_of_bits_get(struct timer_of *to) | ||
77 | { | ||
78 | struct stm32_timer_private *pd = to->private_data; | ||
79 | |||
80 | return pd->bits; | ||
81 | } | ||
82 | |||
47 | static void stm32_clock_event_disable(struct timer_of *to) | 83 | static void stm32_clock_event_disable(struct timer_of *to) |
48 | { | 84 | { |
49 | writel_relaxed(0, timer_of_base(to) + TIM_DIER); | 85 | writel_relaxed(0, timer_of_base(to) + TIM_DIER); |
@@ -124,35 +160,31 @@ static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id) | |||
124 | * is 32 bits wide, the result will be UINT_MAX, otherwise it will | 160 | * is 32 bits wide, the result will be UINT_MAX, otherwise it will |
125 | * be truncated by the 16-bit register to USHRT_MAX. | 161 | * be truncated by the 16-bit register to USHRT_MAX. |
126 | * | 162 | * |
127 | * Returns UINT_MAX if the timer is 32 bits wide, USHRT_MAX if it is a | ||
128 | * 16 bits wide. | ||
129 | */ | 163 | */ |
130 | static u32 __init stm32_timer_width(struct timer_of *to) | 164 | static void __init stm32_timer_set_width(struct timer_of *to) |
131 | { | 165 | { |
166 | u32 width; | ||
167 | |||
132 | writel_relaxed(UINT_MAX, timer_of_base(to) + TIM_ARR); | 168 | writel_relaxed(UINT_MAX, timer_of_base(to) + TIM_ARR); |
133 | 169 | ||
134 | return readl_relaxed(timer_of_base(to) + TIM_ARR); | 170 | width = readl_relaxed(timer_of_base(to) + TIM_ARR); |
171 | |||
172 | stm32_timer_of_bits_set(to, width == UINT_MAX ? 32 : 16); | ||
135 | } | 173 | } |
136 | 174 | ||
137 | static void __init stm32_clockevent_init(struct timer_of *to) | 175 | /** |
176 | * stm32_timer_set_prescaler - Compute and set the prescaler register | ||
177 | * @to: a pointer to a timer-of structure | ||
178 | * | ||
179 | * Depending on the timer width, compute the prescaler to always | ||
180 | * target a 10MHz timer rate for 16 bits. 32-bit timers are | ||
181 | * considered precise and long enough to not use the prescaler. | ||
182 | */ | ||
183 | static void __init stm32_timer_set_prescaler(struct timer_of *to) | ||
138 | { | 184 | { |
139 | u32 width = 0; | 185 | int prescaler = 1; |
140 | int prescaler; | ||
141 | 186 | ||
142 | to->clkevt.name = to->np->full_name; | 187 | if (stm32_timer_of_bits_get(to) != 32) { |
143 | to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC; | ||
144 | to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | ||
145 | to->clkevt.set_state_shutdown = stm32_clock_event_shutdown; | ||
146 | to->clkevt.set_state_periodic = stm32_clock_event_set_periodic; | ||
147 | to->clkevt.set_state_oneshot = stm32_clock_event_set_oneshot; | ||
148 | to->clkevt.tick_resume = stm32_clock_event_shutdown; | ||
149 | to->clkevt.set_next_event = stm32_clock_event_set_next_event; | ||
150 | |||
151 | width = stm32_timer_width(to); | ||
152 | if (width == UINT_MAX) { | ||
153 | prescaler = 1; | ||
154 | to->clkevt.rating = 250; | ||
155 | } else { | ||
156 | prescaler = DIV_ROUND_CLOSEST(timer_of_rate(to), | 188 | prescaler = DIV_ROUND_CLOSEST(timer_of_rate(to), |
157 | TIM_PSC_CLKRATE); | 189 | TIM_PSC_CLKRATE); |
158 | /* | 190 | /* |
@@ -161,7 +193,6 @@ static void __init stm32_clockevent_init(struct timer_of *to) | |||
161 | * this case. | 193 | * this case. |
162 | */ | 194 | */ |
163 | prescaler = prescaler < TIM_PSC_MAX ? prescaler : TIM_PSC_MAX; | 195 | prescaler = prescaler < TIM_PSC_MAX ? prescaler : TIM_PSC_MAX; |
164 | to->clkevt.rating = 100; | ||
165 | } | 196 | } |
166 | 197 | ||
167 | writel_relaxed(prescaler - 1, timer_of_base(to) + TIM_PSC); | 198 | writel_relaxed(prescaler - 1, timer_of_base(to) + TIM_PSC); |
@@ -171,12 +202,26 @@ static void __init stm32_clockevent_init(struct timer_of *to) | |||
171 | /* Adjust rate and period given the prescaler value */ | 202 | /* Adjust rate and period given the prescaler value */ |
172 | to->of_clk.rate = DIV_ROUND_CLOSEST(to->of_clk.rate, prescaler); | 203 | to->of_clk.rate = DIV_ROUND_CLOSEST(to->of_clk.rate, prescaler); |
173 | to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ); | 204 | to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ); |
205 | } | ||
206 | |||
207 | static void __init stm32_clockevent_init(struct timer_of *to) | ||
208 | { | ||
209 | u32 bits = stm32_timer_of_bits_get(to); | ||
174 | 210 | ||
175 | clockevents_config_and_register(&to->clkevt, | 211 | to->clkevt.name = to->np->full_name; |
176 | timer_of_rate(to), 0x1, width); | 212 | to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; |
213 | to->clkevt.set_state_shutdown = stm32_clock_event_shutdown; | ||
214 | to->clkevt.set_state_periodic = stm32_clock_event_set_periodic; | ||
215 | to->clkevt.set_state_oneshot = stm32_clock_event_set_oneshot; | ||
216 | to->clkevt.tick_resume = stm32_clock_event_shutdown; | ||
217 | to->clkevt.set_next_event = stm32_clock_event_set_next_event; | ||
218 | to->clkevt.rating = bits == 32 ? 250 : 100; | ||
219 | |||
220 | clockevents_config_and_register(&to->clkevt, timer_of_rate(to), 0x1, | ||
221 | (1 << bits) - 1); | ||
177 | 222 | ||
178 | pr_info("%pOF: STM32 clockevent driver initialized (%d bits)\n", | 223 | pr_info("%pOF: STM32 clockevent driver initialized (%d bits)\n", |
179 | to->np, width == UINT_MAX ? 32 : 16); | 224 | to->np, bits); |
180 | } | 225 | } |
181 | 226 | ||
182 | static int __init stm32_timer_init(struct device_node *node) | 227 | static int __init stm32_timer_init(struct device_node *node) |
@@ -196,14 +241,26 @@ static int __init stm32_timer_init(struct device_node *node) | |||
196 | if (ret) | 241 | if (ret) |
197 | goto err; | 242 | goto err; |
198 | 243 | ||
244 | to->private_data = kzalloc(sizeof(struct stm32_timer_private), | ||
245 | GFP_KERNEL); | ||
246 | if (!to->private_data) | ||
247 | goto deinit; | ||
248 | |||
199 | rstc = of_reset_control_get(node, NULL); | 249 | rstc = of_reset_control_get(node, NULL); |
200 | if (!IS_ERR(rstc)) { | 250 | if (!IS_ERR(rstc)) { |
201 | reset_control_assert(rstc); | 251 | reset_control_assert(rstc); |
202 | reset_control_deassert(rstc); | 252 | reset_control_deassert(rstc); |
203 | } | 253 | } |
204 | 254 | ||
255 | stm32_timer_set_width(to); | ||
256 | |||
257 | stm32_timer_set_prescaler(to); | ||
258 | |||
205 | stm32_clockevent_init(to); | 259 | stm32_clockevent_init(to); |
206 | return 0; | 260 | return 0; |
261 | |||
262 | deinit: | ||
263 | timer_of_cleanup(to); | ||
207 | err: | 264 | err: |
208 | kfree(to); | 265 | kfree(to); |
209 | return ret; | 266 | return ret; |