1 // SPDX-License-Identifier: GPL-2.0
3 * Allwinner SoCs hstimer driver.
5 * Copyright (C) 2013 Maxime Ripard
7 * Maxime Ripard <maxime.ripard@free-electrons.com>
10 #include <linux/clk.h>
11 #include <linux/clockchips.h>
12 #include <linux/clocksource.h>
13 #include <linux/delay.h>
14 #include <linux/interrupt.h>
15 #include <linux/irq.h>
16 #include <linux/irqreturn.h>
17 #include <linux/reset.h>
18 #include <linux/slab.h>
19 #include <linux/platform_device.h>
21 #define TIMER_IRQ_EN_REG 0x00
22 #define TIMER_IRQ_EN(val) BIT(val)
23 #define TIMER_IRQ_ST_REG 0x04
24 #define TIMER_CTL_REG(val) (0x20 * (val) + 0x10)
25 #define TIMER_CTL_ENABLE BIT(0)
26 #define TIMER_CTL_RELOAD BIT(1)
27 #define TIMER_CTL_CLK_PRES(val) (((val) & 0x7) << 4)
28 #define TIMER_CTL_ONESHOT BIT(7)
29 #define TIMER_INTVAL_LO_REG(val) (0x20 * (val) + 0x14)
30 #define TIMER_INTVAL_HI_REG(val) (0x20 * (val) + 0x18)
31 #define TIMER_CNTVAL_LO_REG(val) (0x20 * (val) + 0x1c)
32 #define TIMER_CNTVAL_HI_REG(val) (0x20 * (val) + 0x20)
34 #define TIMER_SYNC_TICKS 3
39 struct notifier_block clk_rate_cb
;
41 struct clocksource clksrc
;
42 struct clock_event_device clkevt
;
45 #define nb_to_sun5i_timer(x) \
46 container_of(x, struct sun5i_timer, clk_rate_cb)
47 #define clksrc_to_sun5i_timer(x) \
48 container_of(x, struct sun5i_timer, clksrc)
49 #define clkevt_to_sun5i_timer(x) \
50 container_of(x, struct sun5i_timer, clkevt)
53 * When we disable a timer, we need to wait at least for 2 cycles of
54 * the timer source clock. We will use for that the clocksource timer
55 * that is already setup and runs at the same frequency than the other
56 * timers, and we never will be disabled.
58 static void sun5i_clkevt_sync(struct sun5i_timer
*ce
)
60 u32 old
= readl(ce
->base
+ TIMER_CNTVAL_LO_REG(1));
62 while ((old
- readl(ce
->base
+ TIMER_CNTVAL_LO_REG(1))) < TIMER_SYNC_TICKS
)
66 static void sun5i_clkevt_time_stop(struct sun5i_timer
*ce
, u8 timer
)
68 u32 val
= readl(ce
->base
+ TIMER_CTL_REG(timer
));
69 writel(val
& ~TIMER_CTL_ENABLE
, ce
->base
+ TIMER_CTL_REG(timer
));
71 sun5i_clkevt_sync(ce
);
74 static void sun5i_clkevt_time_setup(struct sun5i_timer
*ce
, u8 timer
, u32 delay
)
76 writel(delay
, ce
->base
+ TIMER_INTVAL_LO_REG(timer
));
79 static void sun5i_clkevt_time_start(struct sun5i_timer
*ce
, u8 timer
, bool periodic
)
81 u32 val
= readl(ce
->base
+ TIMER_CTL_REG(timer
));
84 val
&= ~TIMER_CTL_ONESHOT
;
86 val
|= TIMER_CTL_ONESHOT
;
88 writel(val
| TIMER_CTL_ENABLE
| TIMER_CTL_RELOAD
,
89 ce
->base
+ TIMER_CTL_REG(timer
));
92 static int sun5i_clkevt_shutdown(struct clock_event_device
*clkevt
)
94 struct sun5i_timer
*ce
= clkevt_to_sun5i_timer(clkevt
);
96 sun5i_clkevt_time_stop(ce
, 0);
100 static int sun5i_clkevt_set_oneshot(struct clock_event_device
*clkevt
)
102 struct sun5i_timer
*ce
= clkevt_to_sun5i_timer(clkevt
);
104 sun5i_clkevt_time_stop(ce
, 0);
105 sun5i_clkevt_time_start(ce
, 0, false);
109 static int sun5i_clkevt_set_periodic(struct clock_event_device
*clkevt
)
111 struct sun5i_timer
*ce
= clkevt_to_sun5i_timer(clkevt
);
113 sun5i_clkevt_time_stop(ce
, 0);
114 sun5i_clkevt_time_setup(ce
, 0, ce
->ticks_per_jiffy
);
115 sun5i_clkevt_time_start(ce
, 0, true);
119 static int sun5i_clkevt_next_event(unsigned long evt
,
120 struct clock_event_device
*clkevt
)
122 struct sun5i_timer
*ce
= clkevt_to_sun5i_timer(clkevt
);
124 sun5i_clkevt_time_stop(ce
, 0);
125 sun5i_clkevt_time_setup(ce
, 0, evt
- TIMER_SYNC_TICKS
);
126 sun5i_clkevt_time_start(ce
, 0, false);
131 static irqreturn_t
sun5i_timer_interrupt(int irq
, void *dev_id
)
133 struct sun5i_timer
*ce
= dev_id
;
135 writel(0x1, ce
->base
+ TIMER_IRQ_ST_REG
);
136 ce
->clkevt
.event_handler(&ce
->clkevt
);
141 static u64
sun5i_clksrc_read(struct clocksource
*clksrc
)
143 struct sun5i_timer
*cs
= clksrc_to_sun5i_timer(clksrc
);
145 return ~readl(cs
->base
+ TIMER_CNTVAL_LO_REG(1));
148 static int sun5i_rate_cb(struct notifier_block
*nb
,
149 unsigned long event
, void *data
)
151 struct clk_notifier_data
*ndata
= data
;
152 struct sun5i_timer
*cs
= nb_to_sun5i_timer(nb
);
155 case PRE_RATE_CHANGE
:
156 clocksource_unregister(&cs
->clksrc
);
159 case POST_RATE_CHANGE
:
160 clocksource_register_hz(&cs
->clksrc
, ndata
->new_rate
);
161 clockevents_update_freq(&cs
->clkevt
, ndata
->new_rate
);
162 cs
->ticks_per_jiffy
= DIV_ROUND_UP(ndata
->new_rate
, HZ
);
172 static int sun5i_setup_clocksource(struct platform_device
*pdev
,
175 struct sun5i_timer
*cs
= platform_get_drvdata(pdev
);
176 void __iomem
*base
= cs
->base
;
179 writel(~0, base
+ TIMER_INTVAL_LO_REG(1));
180 writel(TIMER_CTL_ENABLE
| TIMER_CTL_RELOAD
,
181 base
+ TIMER_CTL_REG(1));
183 cs
->clksrc
.name
= pdev
->dev
.of_node
->name
;
184 cs
->clksrc
.rating
= 340;
185 cs
->clksrc
.read
= sun5i_clksrc_read
;
186 cs
->clksrc
.mask
= CLOCKSOURCE_MASK(32);
187 cs
->clksrc
.flags
= CLOCK_SOURCE_IS_CONTINUOUS
;
189 ret
= clocksource_register_hz(&cs
->clksrc
, rate
);
191 dev_err(&pdev
->dev
, "Couldn't register clock source.\n");
198 static int sun5i_setup_clockevent(struct platform_device
*pdev
,
199 unsigned long rate
, int irq
)
201 struct device
*dev
= &pdev
->dev
;
202 struct sun5i_timer
*ce
= platform_get_drvdata(pdev
);
203 void __iomem
*base
= ce
->base
;
207 ce
->clkevt
.name
= dev
->of_node
->name
;
208 ce
->clkevt
.features
= CLOCK_EVT_FEAT_PERIODIC
| CLOCK_EVT_FEAT_ONESHOT
;
209 ce
->clkevt
.set_next_event
= sun5i_clkevt_next_event
;
210 ce
->clkevt
.set_state_shutdown
= sun5i_clkevt_shutdown
;
211 ce
->clkevt
.set_state_periodic
= sun5i_clkevt_set_periodic
;
212 ce
->clkevt
.set_state_oneshot
= sun5i_clkevt_set_oneshot
;
213 ce
->clkevt
.tick_resume
= sun5i_clkevt_shutdown
;
214 ce
->clkevt
.rating
= 340;
215 ce
->clkevt
.irq
= irq
;
216 ce
->clkevt
.cpumask
= cpu_possible_mask
;
218 /* Enable timer0 interrupt */
219 val
= readl(base
+ TIMER_IRQ_EN_REG
);
220 writel(val
| TIMER_IRQ_EN(0), base
+ TIMER_IRQ_EN_REG
);
222 clockevents_config_and_register(&ce
->clkevt
, rate
,
223 TIMER_SYNC_TICKS
, 0xffffffff);
225 ret
= devm_request_irq(dev
, irq
, sun5i_timer_interrupt
,
226 IRQF_TIMER
| IRQF_IRQPOLL
,
229 dev_err(dev
, "Unable to register interrupt\n");
236 static int sun5i_timer_probe(struct platform_device
*pdev
)
238 struct device
*dev
= &pdev
->dev
;
239 struct sun5i_timer
*st
;
240 struct reset_control
*rstc
;
241 void __iomem
*timer_base
;
246 st
= devm_kzalloc(dev
, sizeof(*st
), GFP_KERNEL
);
250 platform_set_drvdata(pdev
, st
);
252 timer_base
= devm_platform_ioremap_resource(pdev
, 0);
253 if (IS_ERR(timer_base
)) {
254 dev_err(dev
, "Can't map registers\n");
255 return PTR_ERR(timer_base
);
258 irq
= platform_get_irq(pdev
, 0);
262 clk
= devm_clk_get_enabled(dev
, NULL
);
264 dev_err(dev
, "Can't get timer clock\n");
268 rate
= clk_get_rate(clk
);
270 dev_err(dev
, "Couldn't get parent clock rate\n");
274 st
->base
= timer_base
;
275 st
->ticks_per_jiffy
= DIV_ROUND_UP(rate
, HZ
);
277 st
->clk_rate_cb
.notifier_call
= sun5i_rate_cb
;
278 st
->clk_rate_cb
.next
= NULL
;
280 ret
= devm_clk_notifier_register(dev
, clk
, &st
->clk_rate_cb
);
282 dev_err(dev
, "Unable to register clock notifier.\n");
286 rstc
= devm_reset_control_get_optional_exclusive(dev
, NULL
);
288 reset_control_deassert(rstc
);
290 ret
= sun5i_setup_clocksource(pdev
, rate
);
294 ret
= sun5i_setup_clockevent(pdev
, rate
, irq
);
296 goto err_unreg_clocksource
;
300 err_unreg_clocksource
:
301 clocksource_unregister(&st
->clksrc
);
305 static void sun5i_timer_remove(struct platform_device
*pdev
)
307 struct sun5i_timer
*st
= platform_get_drvdata(pdev
);
309 clocksource_unregister(&st
->clksrc
);
312 static const struct of_device_id sun5i_timer_of_match
[] = {
313 { .compatible
= "allwinner,sun5i-a13-hstimer" },
314 { .compatible
= "allwinner,sun7i-a20-hstimer" },
317 MODULE_DEVICE_TABLE(of
, sun5i_timer_of_match
);
319 static struct platform_driver sun5i_timer_driver
= {
320 .probe
= sun5i_timer_probe
,
321 .remove
= sun5i_timer_remove
,
323 .name
= "sun5i-timer",
324 .of_match_table
= sun5i_timer_of_match
,
325 .suppress_bind_attrs
= true,
328 module_platform_driver(sun5i_timer_driver
);