hc
2023-11-06 e3e12f52b214121840b44c91de5b3e5af5d3eb84
kernel/drivers/clocksource/tcb_clksrc.c
....@@ -25,8 +25,7 @@
2525 * this 32 bit free-running counter. the second channel is not used.
2626 *
2727 * - The third channel may be used to provide a 16-bit clockevent
28
- * source, used in either periodic or oneshot mode. This runs
29
- * at 32 KiHZ, and can handle delays of up to two seconds.
28
+ * source, used in either periodic or oneshot mode.
3029 *
3130 * A boot clocksource and clockevent source are also currently needed,
3231 * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so
....@@ -126,6 +125,8 @@
126125 struct tc_clkevt_device {
127126 struct clock_event_device clkevt;
128127 struct clk *clk;
128
+ bool clk_enabled;
129
+ u32 freq;
129130 void __iomem *regs;
130131 };
131132
....@@ -134,14 +135,25 @@
134135 return container_of(clkevt, struct tc_clkevt_device, clkevt);
135136 }
136137
137
-/* For now, we always use the 32K clock ... this optimizes for NO_HZ,
138
- * because using one of the divided clocks would usually mean the
139
- * tick rate can never be less than several dozen Hz (vs 0.5 Hz).
140
- *
141
- * A divided clock could be good for high resolution timers, since
142
- * 30.5 usec resolution can seem "low".
143
- */
144138 static u32 timer_clock;
139
+
140
+static void tc_clk_disable(struct clock_event_device *d)
141
+{
142
+ struct tc_clkevt_device *tcd = to_tc_clkevt(d);
143
+
144
+ clk_disable(tcd->clk);
145
+ tcd->clk_enabled = false;
146
+}
147
+
148
+static void tc_clk_enable(struct clock_event_device *d)
149
+{
150
+ struct tc_clkevt_device *tcd = to_tc_clkevt(d);
151
+
152
+ if (tcd->clk_enabled)
153
+ return;
154
+ clk_enable(tcd->clk);
155
+ tcd->clk_enabled = true;
156
+}
145157
146158 static int tc_shutdown(struct clock_event_device *d)
147159 {
....@@ -150,8 +162,14 @@
150162
151163 writel(0xff, regs + ATMEL_TC_REG(2, IDR));
152164 writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));
165
+ return 0;
166
+}
167
+
168
+static int tc_shutdown_clk_off(struct clock_event_device *d)
169
+{
170
+ tc_shutdown(d);
153171 if (!clockevent_state_detached(d))
154
- clk_disable(tcd->clk);
172
+ tc_clk_disable(d);
155173
156174 return 0;
157175 }
....@@ -164,9 +182,9 @@
164182 if (clockevent_state_oneshot(d) || clockevent_state_periodic(d))
165183 tc_shutdown(d);
166184
167
- clk_enable(tcd->clk);
185
+ tc_clk_enable(d);
168186
169
- /* slow clock, count up to RC, then irq and stop */
187
+ /* count up to RC, then irq and stop */
170188 writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE |
171189 ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR));
172190 writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
....@@ -186,12 +204,12 @@
186204 /* By not making the gentime core emulate periodic mode on top
187205 * of oneshot, we get lower overhead and improved accuracy.
188206 */
189
- clk_enable(tcd->clk);
207
+ tc_clk_enable(d);
190208
191
- /* slow clock, count up to RC, then irq and restart */
209
+ /* count up to RC, then irq and restart */
192210 writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
193211 regs + ATMEL_TC_REG(2, CMR));
194
- writel((32768 + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
212
+ writel((tcd->freq + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
195213
196214 /* Enable clock and interrupts on RC compare */
197215 writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
....@@ -218,9 +236,13 @@
218236 .features = CLOCK_EVT_FEAT_PERIODIC |
219237 CLOCK_EVT_FEAT_ONESHOT,
220238 /* Should be lower than at91rm9200's system timer */
239
+#ifdef CONFIG_ATMEL_TCB_CLKSRC_USE_SLOW_CLOCK
221240 .rating = 125,
241
+#else
242
+ .rating = 200,
243
+#endif
222244 .set_next_event = tc_next_event,
223
- .set_state_shutdown = tc_shutdown,
245
+ .set_state_shutdown = tc_shutdown_clk_off,
224246 .set_state_periodic = tc_set_periodic,
225247 .set_state_oneshot = tc_set_oneshot,
226248 },
....@@ -240,8 +262,9 @@
240262 return IRQ_NONE;
241263 }
242264
243
-static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
265
+static int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx)
244266 {
267
+ unsigned divisor = atmel_tc_divisors[divisor_idx];
245268 int ret;
246269 struct clk *t2_clk = tc->clk[2];
247270 int irq = tc->irq[2];
....@@ -262,7 +285,11 @@
262285 clkevt.regs = tc->regs;
263286 clkevt.clk = t2_clk;
264287
265
- timer_clock = clk32k_divisor_idx;
288
+ timer_clock = divisor_idx;
289
+ if (!divisor)
290
+ clkevt.freq = 32768;
291
+ else
292
+ clkevt.freq = clk_get_rate(t2_clk) / divisor;
266293
267294 clkevt.clkevt.cpumask = cpumask_of(0);
268295
....@@ -273,7 +300,7 @@
273300 return ret;
274301 }
275302
276
- clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff);
303
+ clockevents_config_and_register(&clkevt.clkevt, clkevt.freq, 1, 0xffff);
277304
278305 return ret;
279306 }
....@@ -410,7 +437,11 @@
410437 goto err_disable_t1;
411438
412439 /* channel 2: periodic and oneshot timer support */
440
+#ifdef CONFIG_ATMEL_TCB_CLKSRC_USE_SLOW_CLOCK
413441 ret = setup_clkevents(tc, clk32k_divisor_idx);
442
+#else
443
+ ret = setup_clkevents(tc, best_divisor_idx);
444
+#endif
414445 if (ret)
415446 goto err_unregister_clksrc;
416447