2 * linux/drivers/clocksource/zevio-timer.c
4 * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
13 #include <linux/irq.h>
15 #include <linux/of_address.h>
16 #include <linux/of_irq.h>
17 #include <linux/clk.h>
18 #include <linux/clockchips.h>
19 #include <linux/cpumask.h>
20 #include <linux/interrupt.h>
21 #include <linux/slab.h>
23 #define IO_CURRENT_VAL 0x00
24 #define IO_DIVIDER 0x04
25 #define IO_CONTROL 0x08
27 #define IO_TIMER1 0x00
28 #define IO_TIMER2 0x0C
30 #define IO_MATCH_BEGIN 0x18
31 #define IO_MATCH(x) (IO_MATCH_BEGIN + ((x) << 2))
33 #define IO_INTR_STS 0x00
34 #define IO_INTR_ACK 0x00
35 #define IO_INTR_MSK 0x04
37 #define CNTL_STOP_TIMER (1 << 4)
38 #define CNTL_RUN_TIMER (0 << 4)
40 #define CNTL_INC (1 << 3)
41 #define CNTL_DEC (0 << 3)
44 #define CNTL_MATCH(x) ((x) + 1)
45 #define CNTL_FOREVER 7
47 /* There are 6 match registers but we only use one. */
50 #define TIMER_INTR_MSK (1 << (TIMER_MATCH))
51 #define TIMER_INTR_ALL 0x3F
55 void __iomem
*timer1
, *timer2
;
56 void __iomem
*interrupt_regs
;
59 struct clock_event_device clkevt
;
60 struct irqaction clkevt_irq
;
62 char clocksource_name
[64];
63 char clockevent_name
[64];
66 static int zevio_timer_set_event(unsigned long delta
,
67 struct clock_event_device
*dev
)
69 struct zevio_timer
*timer
= container_of(dev
, struct zevio_timer
,
72 writel(delta
, timer
->timer1
+ IO_CURRENT_VAL
);
73 writel(CNTL_RUN_TIMER
| CNTL_DEC
| CNTL_MATCH(TIMER_MATCH
),
74 timer
->timer1
+ IO_CONTROL
);
79 static int zevio_timer_shutdown(struct clock_event_device
*dev
)
81 struct zevio_timer
*timer
= container_of(dev
, struct zevio_timer
,
84 /* Disable timer interrupts */
85 writel(0, timer
->interrupt_regs
+ IO_INTR_MSK
);
86 writel(TIMER_INTR_ALL
, timer
->interrupt_regs
+ IO_INTR_ACK
);
88 writel(CNTL_STOP_TIMER
, timer
->timer1
+ IO_CONTROL
);
92 static int zevio_timer_set_oneshot(struct clock_event_device
*dev
)
94 struct zevio_timer
*timer
= container_of(dev
, struct zevio_timer
,
97 /* Enable timer interrupts */
98 writel(TIMER_INTR_MSK
, timer
->interrupt_regs
+ IO_INTR_MSK
);
99 writel(TIMER_INTR_ALL
, timer
->interrupt_regs
+ IO_INTR_ACK
);
103 static irqreturn_t
zevio_timer_interrupt(int irq
, void *dev_id
)
105 struct zevio_timer
*timer
= dev_id
;
108 intr
= readl(timer
->interrupt_regs
+ IO_INTR_ACK
);
109 if (!(intr
& TIMER_INTR_MSK
))
112 writel(TIMER_INTR_MSK
, timer
->interrupt_regs
+ IO_INTR_ACK
);
113 writel(CNTL_STOP_TIMER
, timer
->timer1
+ IO_CONTROL
);
115 if (timer
->clkevt
.event_handler
)
116 timer
->clkevt
.event_handler(&timer
->clkevt
);
121 static int __init
zevio_timer_add(struct device_node
*node
)
123 struct zevio_timer
*timer
;
127 timer
= kzalloc(sizeof(*timer
), GFP_KERNEL
);
131 timer
->base
= of_iomap(node
, 0);
136 timer
->timer1
= timer
->base
+ IO_TIMER1
;
137 timer
->timer2
= timer
->base
+ IO_TIMER2
;
139 timer
->clk
= of_clk_get(node
, 0);
140 if (IS_ERR(timer
->clk
)) {
141 ret
= PTR_ERR(timer
->clk
);
142 pr_err("Timer clock not found! (error %d)\n", ret
);
146 timer
->interrupt_regs
= of_iomap(node
, 1);
147 irqnr
= irq_of_parse_and_map(node
, 0);
149 of_address_to_resource(node
, 0, &res
);
150 scnprintf(timer
->clocksource_name
, sizeof(timer
->clocksource_name
),
151 "%llx.%s_clocksource",
152 (unsigned long long)res
.start
, node
->name
);
154 scnprintf(timer
->clockevent_name
, sizeof(timer
->clockevent_name
),
155 "%llx.%s_clockevent",
156 (unsigned long long)res
.start
, node
->name
);
158 if (timer
->interrupt_regs
&& irqnr
) {
159 timer
->clkevt
.name
= timer
->clockevent_name
;
160 timer
->clkevt
.set_next_event
= zevio_timer_set_event
;
161 timer
->clkevt
.set_state_shutdown
= zevio_timer_shutdown
;
162 timer
->clkevt
.set_state_oneshot
= zevio_timer_set_oneshot
;
163 timer
->clkevt
.tick_resume
= zevio_timer_set_oneshot
;
164 timer
->clkevt
.rating
= 200;
165 timer
->clkevt
.cpumask
= cpu_all_mask
;
166 timer
->clkevt
.features
= CLOCK_EVT_FEAT_ONESHOT
;
167 timer
->clkevt
.irq
= irqnr
;
169 writel(CNTL_STOP_TIMER
, timer
->timer1
+ IO_CONTROL
);
170 writel(0, timer
->timer1
+ IO_DIVIDER
);
172 /* Start with timer interrupts disabled */
173 writel(0, timer
->interrupt_regs
+ IO_INTR_MSK
);
174 writel(TIMER_INTR_ALL
, timer
->interrupt_regs
+ IO_INTR_ACK
);
176 /* Interrupt to occur when timer value matches 0 */
177 writel(0, timer
->base
+ IO_MATCH(TIMER_MATCH
));
179 timer
->clkevt_irq
.name
= timer
->clockevent_name
;
180 timer
->clkevt_irq
.handler
= zevio_timer_interrupt
;
181 timer
->clkevt_irq
.dev_id
= timer
;
182 timer
->clkevt_irq
.flags
= IRQF_TIMER
| IRQF_IRQPOLL
;
184 setup_irq(irqnr
, &timer
->clkevt_irq
);
186 clockevents_config_and_register(&timer
->clkevt
,
187 clk_get_rate(timer
->clk
), 0x0001, 0xffff);
188 pr_info("Added %s as clockevent\n", timer
->clockevent_name
);
191 writel(CNTL_STOP_TIMER
, timer
->timer2
+ IO_CONTROL
);
192 writel(0, timer
->timer2
+ IO_CURRENT_VAL
);
193 writel(0, timer
->timer2
+ IO_DIVIDER
);
194 writel(CNTL_RUN_TIMER
| CNTL_FOREVER
| CNTL_INC
,
195 timer
->timer2
+ IO_CONTROL
);
197 clocksource_mmio_init(timer
->timer2
+ IO_CURRENT_VAL
,
198 timer
->clocksource_name
,
199 clk_get_rate(timer
->clk
),
201 clocksource_mmio_readw_up
);
203 pr_info("Added %s as clocksource\n", timer
->clocksource_name
);
207 iounmap(timer
->base
);
213 static int __init
zevio_timer_init(struct device_node
*node
)
215 return zevio_timer_add(node
);
218 CLOCKSOURCE_OF_DECLARE(zevio_timer
, "lsi,zevio-timer", zevio_timer_init
);