1 // SPDX-License-Identifier: GPL-2.0
3 * 64-bit Periodic Interval Timer driver
5 * Copyright (C) 2019 Microchip Technology Inc. and its subsidiaries
7 * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
10 #include <linux/clk.h>
11 #include <linux/clockchips.h>
12 #include <linux/delay.h>
13 #include <linux/interrupt.h>
14 #include <linux/of_address.h>
15 #include <linux/of_irq.h>
16 #include <linux/sched_clock.h>
17 #include <linux/slab.h>
19 #define MCHP_PIT64B_CR 0x00 /* Control Register */
20 #define MCHP_PIT64B_CR_START BIT(0)
21 #define MCHP_PIT64B_CR_SWRST BIT(8)
23 #define MCHP_PIT64B_MR 0x04 /* Mode Register */
24 #define MCHP_PIT64B_MR_CONT BIT(0)
25 #define MCHP_PIT64B_MR_ONE_SHOT (0)
26 #define MCHP_PIT64B_MR_SGCLK BIT(3)
27 #define MCHP_PIT64B_MR_PRES GENMASK(11, 8)
29 #define MCHP_PIT64B_LSB_PR 0x08 /* LSB Period Register */
31 #define MCHP_PIT64B_MSB_PR 0x0C /* MSB Period Register */
33 #define MCHP_PIT64B_IER 0x10 /* Interrupt Enable Register */
34 #define MCHP_PIT64B_IER_PERIOD BIT(0)
36 #define MCHP_PIT64B_ISR 0x1C /* Interrupt Status Register */
38 #define MCHP_PIT64B_TLSBR 0x20 /* Timer LSB Register */
40 #define MCHP_PIT64B_TMSBR 0x24 /* Timer MSB Register */
42 #define MCHP_PIT64B_PRES_MAX 0x10
43 #define MCHP_PIT64B_LSBMASK GENMASK_ULL(31, 0)
44 #define MCHP_PIT64B_PRES_TO_MODE(p) (MCHP_PIT64B_MR_PRES & ((p) << 8))
45 #define MCHP_PIT64B_MODE_TO_PRES(m) ((MCHP_PIT64B_MR_PRES & (m)) >> 8)
46 #define MCHP_PIT64B_DEF_FREQ 5000000UL /* 5 MHz */
48 #define MCHP_PIT64B_NAME "pit64b"
51 * struct mchp_pit64b_timer - PIT64B timer data structure
52 * @base: base address of PIT64B hardware block
53 * @pclk: PIT64B's peripheral clock
54 * @gclk: PIT64B's generic clock
55 * @mode: precomputed value for mode register
57 struct mchp_pit64b_timer
{
65 * struct mchp_pit64b_clkevt - PIT64B clockevent data structure
66 * @timer: PIT64B timer
69 struct mchp_pit64b_clkevt
{
70 struct mchp_pit64b_timer timer
;
71 struct clock_event_device clkevt
;
74 #define clkevt_to_mchp_pit64b_timer(x) \
75 ((struct mchp_pit64b_timer *)container_of(x,\
76 struct mchp_pit64b_clkevt, clkevt))
79 * struct mchp_pit64b_clksrc - PIT64B clocksource data structure
80 * @timer: PIT64B timer
81 * @clksrc: clocksource
83 struct mchp_pit64b_clksrc
{
84 struct mchp_pit64b_timer timer
;
85 struct clocksource clksrc
;
88 #define clksrc_to_mchp_pit64b_timer(x) \
89 ((struct mchp_pit64b_timer *)container_of(x,\
90 struct mchp_pit64b_clksrc, clksrc))
92 /* Base address for clocksource timer. */
93 static void __iomem
*mchp_pit64b_cs_base
;
94 /* Default cycles for clockevent timer. */
95 static u64 mchp_pit64b_ce_cycles
;
97 static struct delay_timer mchp_pit64b_dt
;
99 static inline u64
mchp_pit64b_cnt_read(void __iomem
*base
)
104 raw_local_irq_save(flags
);
107 * When using a 64 bit period TLSB must be read first, followed by the
108 * read of TMSB. This sequence generates an atomic read of the 64 bit
109 * timer value whatever the lapse of time between the accesses.
111 low
= readl_relaxed(base
+ MCHP_PIT64B_TLSBR
);
112 high
= readl_relaxed(base
+ MCHP_PIT64B_TMSBR
);
114 raw_local_irq_restore(flags
);
116 return (((u64
)high
<< 32) | low
);
119 static inline void mchp_pit64b_reset(struct mchp_pit64b_timer
*timer
,
120 u64 cycles
, u32 mode
, u32 irqs
)
124 low
= cycles
& MCHP_PIT64B_LSBMASK
;
127 writel_relaxed(MCHP_PIT64B_CR_SWRST
, timer
->base
+ MCHP_PIT64B_CR
);
128 writel_relaxed(mode
| timer
->mode
, timer
->base
+ MCHP_PIT64B_MR
);
129 writel_relaxed(high
, timer
->base
+ MCHP_PIT64B_MSB_PR
);
130 writel_relaxed(low
, timer
->base
+ MCHP_PIT64B_LSB_PR
);
131 writel_relaxed(irqs
, timer
->base
+ MCHP_PIT64B_IER
);
132 writel_relaxed(MCHP_PIT64B_CR_START
, timer
->base
+ MCHP_PIT64B_CR
);
135 static void mchp_pit64b_suspend(struct mchp_pit64b_timer
*timer
)
137 writel_relaxed(MCHP_PIT64B_CR_SWRST
, timer
->base
+ MCHP_PIT64B_CR
);
138 if (timer
->mode
& MCHP_PIT64B_MR_SGCLK
)
139 clk_disable_unprepare(timer
->gclk
);
140 clk_disable_unprepare(timer
->pclk
);
143 static void mchp_pit64b_resume(struct mchp_pit64b_timer
*timer
)
145 clk_prepare_enable(timer
->pclk
);
146 if (timer
->mode
& MCHP_PIT64B_MR_SGCLK
)
147 clk_prepare_enable(timer
->gclk
);
150 static void mchp_pit64b_clksrc_suspend(struct clocksource
*cs
)
152 struct mchp_pit64b_timer
*timer
= clksrc_to_mchp_pit64b_timer(cs
);
154 mchp_pit64b_suspend(timer
);
157 static void mchp_pit64b_clksrc_resume(struct clocksource
*cs
)
159 struct mchp_pit64b_timer
*timer
= clksrc_to_mchp_pit64b_timer(cs
);
161 mchp_pit64b_resume(timer
);
162 mchp_pit64b_reset(timer
, ULLONG_MAX
, MCHP_PIT64B_MR_CONT
, 0);
165 static u64
mchp_pit64b_clksrc_read(struct clocksource
*cs
)
167 return mchp_pit64b_cnt_read(mchp_pit64b_cs_base
);
170 static u64 notrace
mchp_pit64b_sched_read_clk(void)
172 return mchp_pit64b_cnt_read(mchp_pit64b_cs_base
);
175 static unsigned long notrace
mchp_pit64b_dt_read(void)
177 return mchp_pit64b_cnt_read(mchp_pit64b_cs_base
);
180 static int mchp_pit64b_clkevt_shutdown(struct clock_event_device
*cedev
)
182 struct mchp_pit64b_timer
*timer
= clkevt_to_mchp_pit64b_timer(cedev
);
184 if (!clockevent_state_detached(cedev
))
185 mchp_pit64b_suspend(timer
);
190 static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device
*cedev
)
192 struct mchp_pit64b_timer
*timer
= clkevt_to_mchp_pit64b_timer(cedev
);
194 if (clockevent_state_shutdown(cedev
))
195 mchp_pit64b_resume(timer
);
197 mchp_pit64b_reset(timer
, mchp_pit64b_ce_cycles
, MCHP_PIT64B_MR_CONT
,
198 MCHP_PIT64B_IER_PERIOD
);
203 static int mchp_pit64b_clkevt_set_oneshot(struct clock_event_device
*cedev
)
205 struct mchp_pit64b_timer
*timer
= clkevt_to_mchp_pit64b_timer(cedev
);
207 if (clockevent_state_shutdown(cedev
))
208 mchp_pit64b_resume(timer
);
210 mchp_pit64b_reset(timer
, mchp_pit64b_ce_cycles
, MCHP_PIT64B_MR_ONE_SHOT
,
211 MCHP_PIT64B_IER_PERIOD
);
216 static int mchp_pit64b_clkevt_set_next_event(unsigned long evt
,
217 struct clock_event_device
*cedev
)
219 struct mchp_pit64b_timer
*timer
= clkevt_to_mchp_pit64b_timer(cedev
);
221 mchp_pit64b_reset(timer
, evt
, MCHP_PIT64B_MR_ONE_SHOT
,
222 MCHP_PIT64B_IER_PERIOD
);
227 static irqreturn_t
mchp_pit64b_interrupt(int irq
, void *dev_id
)
229 struct mchp_pit64b_clkevt
*irq_data
= dev_id
;
231 /* Need to clear the interrupt. */
232 readl_relaxed(irq_data
->timer
.base
+ MCHP_PIT64B_ISR
);
234 irq_data
->clkevt
.event_handler(&irq_data
->clkevt
);
239 static void __init
mchp_pit64b_pres_compute(u32
*pres
, u32 clk_rate
,
244 for (*pres
= 0; *pres
< MCHP_PIT64B_PRES_MAX
; (*pres
)++) {
245 tmp
= clk_rate
/ (*pres
+ 1);
250 /* Use the biggest prescaler if we didn't match one. */
251 if (*pres
== MCHP_PIT64B_PRES_MAX
)
252 *pres
= MCHP_PIT64B_PRES_MAX
- 1;
256 * mchp_pit64b_init_mode() - prepare PIT64B mode register value to be used at
257 * runtime; this includes prescaler and SGCLK bit
258 * @timer: pointer to pit64b timer to init
259 * @max_rate: maximum rate that timer's clock could use
261 * PIT64B timer may be fed by gclk or pclk. When gclk is used its rate has to
262 * be at least 3 times lower that pclk's rate. pclk rate is fixed, gclk rate
263 * could be changed via clock APIs. The chosen clock (pclk or gclk) could be
264 * divided by the internal PIT64B's divider.
266 * This function, first tries to use GCLK by requesting the desired rate from
267 * PMC and then using the internal PIT64B prescaler, if any, to reach the
268 * requested rate. If PCLK/GCLK < 3 (condition requested by PIT64B hardware)
269 * then the function falls back on using PCLK as clock source for PIT64B timer
270 * choosing the highest prescaler in case it doesn't locate one to match the
271 * requested frequency.
273 * Below is presented the PIT64B block in relation with PMC:
276 * PMC +------------------------------------+
278 * | |-->gclk -->|-->| | +---------+ +-----+ |
279 * | | | | MUX |--->| Divider |->|timer| |
280 * | |-->pclk -->|-->| | +---------+ +-----+ |
284 * +------------------------------------+
287 * - gclk rate <= pclk rate/3
288 * - gclk rate could be requested from PMC
289 * - pclk rate is fixed (cannot be requested from PMC)
291 static int __init
mchp_pit64b_init_mode(struct mchp_pit64b_timer
*timer
,
292 unsigned long max_rate
)
294 unsigned long pclk_rate
, diff
= 0, best_diff
= ULONG_MAX
;
296 u32 pres
, best_pres
= 0;
298 pclk_rate
= clk_get_rate(timer
->pclk
);
304 /* Try using GCLK. */
305 gclk_round
= clk_round_rate(timer
->gclk
, max_rate
);
309 if (pclk_rate
/ gclk_round
< 3)
312 mchp_pit64b_pres_compute(&pres
, gclk_round
, max_rate
);
313 best_diff
= abs(gclk_round
/ (pres
+ 1) - max_rate
);
317 timer
->mode
|= MCHP_PIT64B_MR_SGCLK
;
318 clk_set_rate(timer
->gclk
, gclk_round
);
323 /* Check if requested rate could be obtained using PCLK. */
324 mchp_pit64b_pres_compute(&pres
, pclk_rate
, max_rate
);
325 diff
= abs(pclk_rate
/ (pres
+ 1) - max_rate
);
327 if (best_diff
> diff
) {
332 timer
->mode
|= MCHP_PIT64B_MR_SGCLK
;
333 clk_set_rate(timer
->gclk
, gclk_round
);
337 timer
->mode
|= MCHP_PIT64B_PRES_TO_MODE(best_pres
);
339 pr_info("PIT64B: using clk=%s with prescaler %u, freq=%lu [Hz]\n",
340 timer
->mode
& MCHP_PIT64B_MR_SGCLK
? "gclk" : "pclk", best_pres
,
341 timer
->mode
& MCHP_PIT64B_MR_SGCLK
?
342 gclk_round
/ (best_pres
+ 1) : pclk_rate
/ (best_pres
+ 1));
347 static int __init
mchp_pit64b_init_clksrc(struct mchp_pit64b_timer
*timer
,
350 struct mchp_pit64b_clksrc
*cs
;
353 cs
= kzalloc(sizeof(*cs
), GFP_KERNEL
);
357 mchp_pit64b_resume(timer
);
358 mchp_pit64b_reset(timer
, ULLONG_MAX
, MCHP_PIT64B_MR_CONT
, 0);
360 mchp_pit64b_cs_base
= timer
->base
;
362 cs
->timer
.base
= timer
->base
;
363 cs
->timer
.pclk
= timer
->pclk
;
364 cs
->timer
.gclk
= timer
->gclk
;
365 cs
->timer
.mode
= timer
->mode
;
366 cs
->clksrc
.name
= MCHP_PIT64B_NAME
;
367 cs
->clksrc
.mask
= CLOCKSOURCE_MASK(64);
368 cs
->clksrc
.flags
= CLOCK_SOURCE_IS_CONTINUOUS
;
369 cs
->clksrc
.rating
= 210;
370 cs
->clksrc
.read
= mchp_pit64b_clksrc_read
;
371 cs
->clksrc
.suspend
= mchp_pit64b_clksrc_suspend
;
372 cs
->clksrc
.resume
= mchp_pit64b_clksrc_resume
;
374 ret
= clocksource_register_hz(&cs
->clksrc
, clk_rate
);
376 pr_debug("clksrc: Failed to register PIT64B clocksource!\n");
379 mchp_pit64b_suspend(timer
);
385 sched_clock_register(mchp_pit64b_sched_read_clk
, 64, clk_rate
);
387 mchp_pit64b_dt
.read_current_timer
= mchp_pit64b_dt_read
;
388 mchp_pit64b_dt
.freq
= clk_rate
;
389 register_current_timer_delay(&mchp_pit64b_dt
);
394 static int __init
mchp_pit64b_init_clkevt(struct mchp_pit64b_timer
*timer
,
395 u32 clk_rate
, u32 irq
)
397 struct mchp_pit64b_clkevt
*ce
;
400 ce
= kzalloc(sizeof(*ce
), GFP_KERNEL
);
404 mchp_pit64b_ce_cycles
= DIV_ROUND_CLOSEST(clk_rate
, HZ
);
406 ce
->timer
.base
= timer
->base
;
407 ce
->timer
.pclk
= timer
->pclk
;
408 ce
->timer
.gclk
= timer
->gclk
;
409 ce
->timer
.mode
= timer
->mode
;
410 ce
->clkevt
.name
= MCHP_PIT64B_NAME
;
411 ce
->clkevt
.features
= CLOCK_EVT_FEAT_ONESHOT
| CLOCK_EVT_FEAT_PERIODIC
;
412 ce
->clkevt
.rating
= 150;
413 ce
->clkevt
.set_state_shutdown
= mchp_pit64b_clkevt_shutdown
;
414 ce
->clkevt
.set_state_periodic
= mchp_pit64b_clkevt_set_periodic
;
415 ce
->clkevt
.set_state_oneshot
= mchp_pit64b_clkevt_set_oneshot
;
416 ce
->clkevt
.set_next_event
= mchp_pit64b_clkevt_set_next_event
;
417 ce
->clkevt
.cpumask
= cpumask_of(0);
418 ce
->clkevt
.irq
= irq
;
420 ret
= request_irq(irq
, mchp_pit64b_interrupt
, IRQF_TIMER
,
423 pr_debug("clkevt: Failed to setup PIT64B IRQ\n");
428 clockevents_config_and_register(&ce
->clkevt
, clk_rate
, 1, ULONG_MAX
);
433 static int __init
mchp_pit64b_dt_init_timer(struct device_node
*node
,
436 struct mchp_pit64b_timer timer
;
437 unsigned long clk_rate
;
442 timer
.pclk
= of_clk_get_by_name(node
, "pclk");
443 if (IS_ERR(timer
.pclk
))
444 return PTR_ERR(timer
.pclk
);
446 timer
.gclk
= of_clk_get_by_name(node
, "gclk");
447 if (IS_ERR(timer
.gclk
))
448 return PTR_ERR(timer
.gclk
);
450 timer
.base
= of_iomap(node
, 0);
455 irq
= irq_of_parse_and_map(node
, 0);
462 /* Initialize mode (prescaler + SGCK bit). To be used at runtime. */
463 ret
= mchp_pit64b_init_mode(&timer
, MCHP_PIT64B_DEF_FREQ
);
467 if (timer
.mode
& MCHP_PIT64B_MR_SGCLK
)
468 clk_rate
= clk_get_rate(timer
.gclk
);
470 clk_rate
= clk_get_rate(timer
.pclk
);
471 clk_rate
= clk_rate
/ (MCHP_PIT64B_MODE_TO_PRES(timer
.mode
) + 1);
474 ret
= mchp_pit64b_init_clkevt(&timer
, clk_rate
, irq
);
476 ret
= mchp_pit64b_init_clksrc(&timer
, clk_rate
);
484 irq_dispose_mapping(irq
);
491 static int __init
mchp_pit64b_dt_init(struct device_node
*node
)
497 /* 1st request, register clockevent. */
498 return mchp_pit64b_dt_init_timer(node
, true);
500 /* 2nd request, register clocksource. */
501 return mchp_pit64b_dt_init_timer(node
, false);
504 /* The rest, don't care. */
508 TIMER_OF_DECLARE(mchp_pit64b
, "microchip,sam9x60-pit64b", mchp_pit64b_dt_init
);