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/interrupt.h>
13 #include <linux/of_address.h>
14 #include <linux/of_irq.h>
15 #include <linux/sched_clock.h>
16 #include <linux/slab.h>
18 #define MCHP_PIT64B_CR 0x00 /* Control Register */
19 #define MCHP_PIT64B_CR_START BIT(0)
20 #define MCHP_PIT64B_CR_SWRST BIT(8)
22 #define MCHP_PIT64B_MR 0x04 /* Mode Register */
23 #define MCHP_PIT64B_MR_CONT BIT(0)
24 #define MCHP_PIT64B_MR_ONE_SHOT (0)
25 #define MCHP_PIT64B_MR_SGCLK BIT(3)
26 #define MCHP_PIT64B_MR_PRES GENMASK(11, 8)
28 #define MCHP_PIT64B_LSB_PR 0x08 /* LSB Period Register */
30 #define MCHP_PIT64B_MSB_PR 0x0C /* MSB Period Register */
32 #define MCHP_PIT64B_IER 0x10 /* Interrupt Enable Register */
33 #define MCHP_PIT64B_IER_PERIOD BIT(0)
35 #define MCHP_PIT64B_ISR 0x1C /* Interrupt Status Register */
37 #define MCHP_PIT64B_TLSBR 0x20 /* Timer LSB Register */
39 #define MCHP_PIT64B_TMSBR 0x24 /* Timer MSB Register */
41 #define MCHP_PIT64B_PRES_MAX 0x10
42 #define MCHP_PIT64B_LSBMASK GENMASK_ULL(31, 0)
43 #define MCHP_PIT64B_PRES_TO_MODE(p) (MCHP_PIT64B_MR_PRES & ((p) << 8))
44 #define MCHP_PIT64B_MODE_TO_PRES(m) ((MCHP_PIT64B_MR_PRES & (m)) >> 8)
45 #define MCHP_PIT64B_DEF_CS_FREQ 5000000UL /* 5 MHz */
46 #define MCHP_PIT64B_DEF_CE_FREQ 32768 /* 32 KHz */
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 * 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 to_mchp_pit64b_timer(x) \
75 ((struct mchp_pit64b_timer *)container_of(x,\
76 struct mchp_pit64b_clkevt, clkevt))
78 /* Base address for clocksource timer. */
79 static void __iomem
*mchp_pit64b_cs_base
;
80 /* Default cycles for clockevent timer. */
81 static u64 mchp_pit64b_ce_cycles
;
83 static inline u64
mchp_pit64b_cnt_read(void __iomem
*base
)
88 raw_local_irq_save(flags
);
91 * When using a 64 bit period TLSB must be read first, followed by the
92 * read of TMSB. This sequence generates an atomic read of the 64 bit
93 * timer value whatever the lapse of time between the accesses.
95 low
= readl_relaxed(base
+ MCHP_PIT64B_TLSBR
);
96 high
= readl_relaxed(base
+ MCHP_PIT64B_TMSBR
);
98 raw_local_irq_restore(flags
);
100 return (((u64
)high
<< 32) | low
);
103 static inline void mchp_pit64b_reset(struct mchp_pit64b_timer
*timer
,
104 u64 cycles
, u32 mode
, u32 irqs
)
108 low
= cycles
& MCHP_PIT64B_LSBMASK
;
111 writel_relaxed(MCHP_PIT64B_CR_SWRST
, timer
->base
+ MCHP_PIT64B_CR
);
112 writel_relaxed(mode
| timer
->mode
, timer
->base
+ MCHP_PIT64B_MR
);
113 writel_relaxed(high
, timer
->base
+ MCHP_PIT64B_MSB_PR
);
114 writel_relaxed(low
, timer
->base
+ MCHP_PIT64B_LSB_PR
);
115 writel_relaxed(irqs
, timer
->base
+ MCHP_PIT64B_IER
);
116 writel_relaxed(MCHP_PIT64B_CR_START
, timer
->base
+ MCHP_PIT64B_CR
);
119 static u64
mchp_pit64b_clksrc_read(struct clocksource
*cs
)
121 return mchp_pit64b_cnt_read(mchp_pit64b_cs_base
);
124 static u64
mchp_pit64b_sched_read_clk(void)
126 return mchp_pit64b_cnt_read(mchp_pit64b_cs_base
);
129 static int mchp_pit64b_clkevt_shutdown(struct clock_event_device
*cedev
)
131 struct mchp_pit64b_timer
*timer
= to_mchp_pit64b_timer(cedev
);
133 writel_relaxed(MCHP_PIT64B_CR_SWRST
, timer
->base
+ MCHP_PIT64B_CR
);
138 static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device
*cedev
)
140 struct mchp_pit64b_timer
*timer
= to_mchp_pit64b_timer(cedev
);
142 mchp_pit64b_reset(timer
, mchp_pit64b_ce_cycles
, MCHP_PIT64B_MR_CONT
,
143 MCHP_PIT64B_IER_PERIOD
);
148 static int mchp_pit64b_clkevt_set_next_event(unsigned long evt
,
149 struct clock_event_device
*cedev
)
151 struct mchp_pit64b_timer
*timer
= to_mchp_pit64b_timer(cedev
);
153 mchp_pit64b_reset(timer
, evt
, MCHP_PIT64B_MR_ONE_SHOT
,
154 MCHP_PIT64B_IER_PERIOD
);
159 static void mchp_pit64b_clkevt_suspend(struct clock_event_device
*cedev
)
161 struct mchp_pit64b_timer
*timer
= to_mchp_pit64b_timer(cedev
);
163 writel_relaxed(MCHP_PIT64B_CR_SWRST
, timer
->base
+ MCHP_PIT64B_CR
);
164 if (timer
->mode
& MCHP_PIT64B_MR_SGCLK
)
165 clk_disable_unprepare(timer
->gclk
);
166 clk_disable_unprepare(timer
->pclk
);
169 static void mchp_pit64b_clkevt_resume(struct clock_event_device
*cedev
)
171 struct mchp_pit64b_timer
*timer
= to_mchp_pit64b_timer(cedev
);
173 clk_prepare_enable(timer
->pclk
);
174 if (timer
->mode
& MCHP_PIT64B_MR_SGCLK
)
175 clk_prepare_enable(timer
->gclk
);
178 static irqreturn_t
mchp_pit64b_interrupt(int irq
, void *dev_id
)
180 struct mchp_pit64b_clkevt
*irq_data
= dev_id
;
182 /* Need to clear the interrupt. */
183 readl_relaxed(irq_data
->timer
.base
+ MCHP_PIT64B_ISR
);
185 irq_data
->clkevt
.event_handler(&irq_data
->clkevt
);
190 static void __init
mchp_pit64b_pres_compute(u32
*pres
, u32 clk_rate
,
195 for (*pres
= 0; *pres
< MCHP_PIT64B_PRES_MAX
; (*pres
)++) {
196 tmp
= clk_rate
/ (*pres
+ 1);
201 /* Use the bigest prescaler if we didn't match one. */
202 if (*pres
== MCHP_PIT64B_PRES_MAX
)
203 *pres
= MCHP_PIT64B_PRES_MAX
- 1;
207 * mchp_pit64b_init_mode - prepare PIT64B mode register value to be used at
208 * runtime; this includes prescaler and SGCLK bit
210 * PIT64B timer may be fed by gclk or pclk. When gclk is used its rate has to
211 * be at least 3 times lower that pclk's rate. pclk rate is fixed, gclk rate
212 * could be changed via clock APIs. The chosen clock (pclk or gclk) could be
213 * divided by the internal PIT64B's divider.
215 * This function, first tries to use GCLK by requesting the desired rate from
216 * PMC and then using the internal PIT64B prescaler, if any, to reach the
217 * requested rate. If PCLK/GCLK < 3 (condition requested by PIT64B hardware)
218 * then the function falls back on using PCLK as clock source for PIT64B timer
219 * choosing the highest prescaler in case it doesn't locate one to match the
220 * requested frequency.
222 * Below is presented the PIT64B block in relation with PMC:
225 * PMC +------------------------------------+
227 * | |-->gclk -->|-->| | +---------+ +-----+ |
228 * | | | | MUX |--->| Divider |->|timer| |
229 * | |-->pclk -->|-->| | +---------+ +-----+ |
233 * +------------------------------------+
236 * - gclk rate <= pclk rate/3
237 * - gclk rate could be requested from PMC
238 * - pclk rate is fixed (cannot be requested from PMC)
240 static int __init
mchp_pit64b_init_mode(struct mchp_pit64b_timer
*timer
,
241 unsigned long max_rate
)
243 unsigned long pclk_rate
, diff
= 0, best_diff
= ULONG_MAX
;
245 u32 pres
, best_pres
= 0;
247 pclk_rate
= clk_get_rate(timer
->pclk
);
253 /* Try using GCLK. */
254 gclk_round
= clk_round_rate(timer
->gclk
, max_rate
);
258 if (pclk_rate
/ gclk_round
< 3)
261 mchp_pit64b_pres_compute(&pres
, gclk_round
, max_rate
);
262 best_diff
= abs(gclk_round
/ (pres
+ 1) - max_rate
);
266 timer
->mode
|= MCHP_PIT64B_MR_SGCLK
;
271 /* Check if requested rate could be obtained using PCLK. */
272 mchp_pit64b_pres_compute(&pres
, pclk_rate
, max_rate
);
273 diff
= abs(pclk_rate
/ (pres
+ 1) - max_rate
);
275 if (best_diff
> diff
) {
280 timer
->mode
|= MCHP_PIT64B_MR_SGCLK
;
281 clk_set_rate(timer
->gclk
, gclk_round
);
285 timer
->mode
|= MCHP_PIT64B_PRES_TO_MODE(best_pres
);
287 pr_info("PIT64B: using clk=%s with prescaler %u, freq=%lu [Hz]\n",
288 timer
->mode
& MCHP_PIT64B_MR_SGCLK
? "gclk" : "pclk", best_pres
,
289 timer
->mode
& MCHP_PIT64B_MR_SGCLK
?
290 gclk_round
/ (best_pres
+ 1) : pclk_rate
/ (best_pres
+ 1));
295 static int __init
mchp_pit64b_init_clksrc(struct mchp_pit64b_timer
*timer
,
300 mchp_pit64b_reset(timer
, ULLONG_MAX
, MCHP_PIT64B_MR_CONT
, 0);
302 mchp_pit64b_cs_base
= timer
->base
;
304 ret
= clocksource_mmio_init(timer
->base
, MCHP_PIT64B_NAME
, clk_rate
,
305 210, 64, mchp_pit64b_clksrc_read
);
307 pr_debug("clksrc: Failed to register PIT64B clocksource!\n");
310 writel_relaxed(MCHP_PIT64B_CR_SWRST
,
311 timer
->base
+ MCHP_PIT64B_CR
);
316 sched_clock_register(mchp_pit64b_sched_read_clk
, 64, clk_rate
);
321 static int __init
mchp_pit64b_init_clkevt(struct mchp_pit64b_timer
*timer
,
322 u32 clk_rate
, u32 irq
)
324 struct mchp_pit64b_clkevt
*ce
;
327 ce
= kzalloc(sizeof(*ce
), GFP_KERNEL
);
331 mchp_pit64b_ce_cycles
= DIV_ROUND_CLOSEST(clk_rate
, HZ
);
333 ce
->timer
.base
= timer
->base
;
334 ce
->timer
.pclk
= timer
->pclk
;
335 ce
->timer
.gclk
= timer
->gclk
;
336 ce
->timer
.mode
= timer
->mode
;
337 ce
->clkevt
.name
= MCHP_PIT64B_NAME
;
338 ce
->clkevt
.features
= CLOCK_EVT_FEAT_ONESHOT
| CLOCK_EVT_FEAT_PERIODIC
;
339 ce
->clkevt
.rating
= 150;
340 ce
->clkevt
.set_state_shutdown
= mchp_pit64b_clkevt_shutdown
;
341 ce
->clkevt
.set_state_periodic
= mchp_pit64b_clkevt_set_periodic
;
342 ce
->clkevt
.set_next_event
= mchp_pit64b_clkevt_set_next_event
;
343 ce
->clkevt
.suspend
= mchp_pit64b_clkevt_suspend
;
344 ce
->clkevt
.resume
= mchp_pit64b_clkevt_resume
;
345 ce
->clkevt
.cpumask
= cpumask_of(0);
346 ce
->clkevt
.irq
= irq
;
348 ret
= request_irq(irq
, mchp_pit64b_interrupt
, IRQF_TIMER
,
351 pr_debug("clkevt: Failed to setup PIT64B IRQ\n");
356 clockevents_config_and_register(&ce
->clkevt
, clk_rate
, 1, ULONG_MAX
);
361 static int __init
mchp_pit64b_dt_init_timer(struct device_node
*node
,
364 u32 freq
= clkevt
? MCHP_PIT64B_DEF_CE_FREQ
: MCHP_PIT64B_DEF_CS_FREQ
;
365 struct mchp_pit64b_timer timer
;
366 unsigned long clk_rate
;
371 timer
.pclk
= of_clk_get_by_name(node
, "pclk");
372 if (IS_ERR(timer
.pclk
))
373 return PTR_ERR(timer
.pclk
);
375 timer
.gclk
= of_clk_get_by_name(node
, "gclk");
376 if (IS_ERR(timer
.gclk
))
377 return PTR_ERR(timer
.gclk
);
379 timer
.base
= of_iomap(node
, 0);
384 irq
= irq_of_parse_and_map(node
, 0);
391 /* Initialize mode (prescaler + SGCK bit). To be used at runtime. */
392 ret
= mchp_pit64b_init_mode(&timer
, freq
);
396 ret
= clk_prepare_enable(timer
.pclk
);
400 if (timer
.mode
& MCHP_PIT64B_MR_SGCLK
) {
401 ret
= clk_prepare_enable(timer
.gclk
);
405 clk_rate
= clk_get_rate(timer
.gclk
);
407 clk_rate
= clk_get_rate(timer
.pclk
);
409 clk_rate
= clk_rate
/ (MCHP_PIT64B_MODE_TO_PRES(timer
.mode
) + 1);
412 ret
= mchp_pit64b_init_clkevt(&timer
, clk_rate
, irq
);
414 ret
= mchp_pit64b_init_clksrc(&timer
, clk_rate
);
422 if (timer
.mode
& MCHP_PIT64B_MR_SGCLK
)
423 clk_disable_unprepare(timer
.gclk
);
425 clk_disable_unprepare(timer
.pclk
);
427 irq_dispose_mapping(irq
);
434 static int __init
mchp_pit64b_dt_init(struct device_node
*node
)
440 /* 1st request, register clockevent. */
441 return mchp_pit64b_dt_init_timer(node
, true);
443 /* 2nd request, register clocksource. */
444 return mchp_pit64b_dt_init_timer(node
, false);
447 /* The rest, don't care. */
451 TIMER_OF_DECLARE(mchp_pit64b
, "microchip,sam9x60-pit64b", mchp_pit64b_dt_init
);