1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2005-2017 Andes Technology Corporation
4 * Andestech ATCPIT100 Timer Device Driver Implementation
5 * Rick Chen, Andes Technology Corporation <rick@andestech.com>
10 #include <linux/clocksource.h>
11 #include <linux/clockchips.h>
12 #include <linux/interrupt.h>
13 #include <linux/ioport.h>
14 #include <linux/cpufreq.h>
15 #include <linux/sched.h>
16 #include <linux/sched_clock.h>
17 #include <linux/of_address.h>
18 #include <linux/of_irq.h>
19 #include <linux/of_platform.h>
22 #include <asm/vdso_timer_info.h>
26 * Definition of register offsets
29 /* ID and Revision Register */
32 /* Configuration Register */
35 /* Interrupt Enable Register */
37 #define CH_INT_EN(c, i) ((1<<i)<<(4*c))
38 #define CH0INT0EN 0x01
40 /* Interrupt Status Register */
44 /* Channel Enable Register */
47 #define CH1TMR0EN 0x10
49 /* Channel 0 , 1 Control Register */
50 #define CH0_CTL (0x20)
51 #define CH1_CTL (0x20 + 0x10)
53 /* Channel clock source , bit 3 , 0:External clock , 1:APB clock */
54 #define APB_CLK BIT(3)
56 /* Channel mode , bit 0~2 */
61 /* Channel 0 , 1 Reload Register */
62 #define CH0_REL (0x24)
63 #define CH1_REL (0x24 + 0x10)
65 /* Channel 0 , 1 Counter Register */
66 #define CH0_CNT (0x28)
67 #define CH1_CNT (0x28 + 0x10)
69 #define TIMER_SYNC_TICKS 3
71 static void atcpit100_ch1_tmr0_en(void __iomem
*base
)
73 writel(~0, base
+ CH1_REL
);
74 writel(APB_CLK
|TMR_32
, base
+ CH1_CTL
);
77 static void atcpit100_ch0_tmr0_en(void __iomem
*base
)
79 writel(APB_CLK
|TMR_32
, base
+ CH0_CTL
);
82 static void atcpit100_clkevt_time_setup(void __iomem
*base
, unsigned long delay
)
84 writel(delay
, base
+ CH0_CNT
);
85 writel(delay
, base
+ CH0_REL
);
88 static void atcpit100_timer_clear_interrupt(void __iomem
*base
)
92 val
= readl(base
+ INT_STA
);
93 writel(val
| CH0INT0
, base
+ INT_STA
);
96 static void atcpit100_clocksource_start(void __iomem
*base
)
100 val
= readl(base
+ CH_EN
);
101 writel(val
| CH1TMR0EN
, base
+ CH_EN
);
104 static void atcpit100_clkevt_time_start(void __iomem
*base
)
108 val
= readl(base
+ CH_EN
);
109 writel(val
| CH0TMR0EN
, base
+ CH_EN
);
112 static void atcpit100_clkevt_time_stop(void __iomem
*base
)
116 atcpit100_timer_clear_interrupt(base
);
117 val
= readl(base
+ CH_EN
);
118 writel(val
& ~CH0TMR0EN
, base
+ CH_EN
);
121 static int atcpit100_clkevt_next_event(unsigned long evt
,
122 struct clock_event_device
*clkevt
)
125 struct timer_of
*to
= to_timer_of(clkevt
);
127 val
= readl(timer_of_base(to
) + CH_EN
);
128 writel(val
& ~CH0TMR0EN
, timer_of_base(to
) + CH_EN
);
129 writel(evt
, timer_of_base(to
) + CH0_REL
);
130 writel(val
| CH0TMR0EN
, timer_of_base(to
) + CH_EN
);
135 static int atcpit100_clkevt_set_periodic(struct clock_event_device
*evt
)
137 struct timer_of
*to
= to_timer_of(evt
);
139 atcpit100_clkevt_time_setup(timer_of_base(to
), timer_of_period(to
));
140 atcpit100_clkevt_time_start(timer_of_base(to
));
144 static int atcpit100_clkevt_shutdown(struct clock_event_device
*evt
)
146 struct timer_of
*to
= to_timer_of(evt
);
148 atcpit100_clkevt_time_stop(timer_of_base(to
));
152 static int atcpit100_clkevt_set_oneshot(struct clock_event_device
*evt
)
154 struct timer_of
*to
= to_timer_of(evt
);
157 writel(~0x0, timer_of_base(to
) + CH0_REL
);
158 val
= readl(timer_of_base(to
) + CH_EN
);
159 writel(val
| CH0TMR0EN
, timer_of_base(to
) + CH_EN
);
164 static irqreturn_t
atcpit100_timer_interrupt(int irq
, void *dev_id
)
166 struct clock_event_device
*evt
= (struct clock_event_device
*)dev_id
;
167 struct timer_of
*to
= to_timer_of(evt
);
169 atcpit100_timer_clear_interrupt(timer_of_base(to
));
171 evt
->event_handler(evt
);
176 static struct timer_of to
= {
177 .flags
= TIMER_OF_IRQ
| TIMER_OF_CLOCK
| TIMER_OF_BASE
,
180 .name
= "atcpit100_tick",
182 .features
= CLOCK_EVT_FEAT_PERIODIC
| CLOCK_EVT_FEAT_ONESHOT
,
183 .set_state_shutdown
= atcpit100_clkevt_shutdown
,
184 .set_state_periodic
= atcpit100_clkevt_set_periodic
,
185 .set_state_oneshot
= atcpit100_clkevt_set_oneshot
,
186 .tick_resume
= atcpit100_clkevt_shutdown
,
187 .set_next_event
= atcpit100_clkevt_next_event
,
188 .cpumask
= cpu_possible_mask
,
192 .handler
= atcpit100_timer_interrupt
,
193 .flags
= IRQF_TIMER
| IRQF_IRQPOLL
,
197 * FIXME: we currently only support clocking using PCLK
198 * and using EXTCLK is not supported in the driver.
205 static u64 notrace
atcpit100_timer_sched_read(void)
207 return ~readl(timer_of_base(&to
) + CH1_CNT
);
211 static void fill_vdso_need_info(struct device_node
*node
)
213 struct resource timer_res
;
214 of_address_to_resource(node
, 0, &timer_res
);
215 timer_info
.mapping_base
= (unsigned long)timer_res
.start
;
216 timer_info
.cycle_count_down
= true;
217 timer_info
.cycle_count_reg_offset
= CH1_CNT
;
221 static int __init
atcpit100_timer_init(struct device_node
*node
)
227 ret
= timer_of_init(node
, &to
);
231 base
= timer_of_base(&to
);
233 sched_clock_register(atcpit100_timer_sched_read
, 32,
236 ret
= clocksource_mmio_init(base
+ CH1_CNT
,
237 node
->name
, timer_of_rate(&to
), 300, 32,
238 clocksource_mmio_readl_down
);
241 pr_err("Failed to register clocksource\n");
245 /* clear channel 0 timer0 interrupt */
246 atcpit100_timer_clear_interrupt(base
);
248 clockevents_config_and_register(&to
.clkevt
, timer_of_rate(&to
),
249 TIMER_SYNC_TICKS
, 0xffffffff);
250 atcpit100_ch0_tmr0_en(base
);
251 atcpit100_ch1_tmr0_en(base
);
252 atcpit100_clocksource_start(base
);
253 atcpit100_clkevt_time_start(base
);
255 /* Enable channel 0 timer0 interrupt */
256 val
= readl(base
+ INT_EN
);
257 writel(val
| CH0INT0EN
, base
+ INT_EN
);
260 fill_vdso_need_info(node
);
266 TIMER_OF_DECLARE(atcpit100
, "andestech,atcpit100", atcpit100_timer_init
);