diff options
Diffstat (limited to 'drivers/clocksource/timer-keystone.c')
-rw-r--r-- | drivers/clocksource/timer-keystone.c | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c new file mode 100644 index 000000000000..0250354f7e55 --- /dev/null +++ b/drivers/clocksource/timer-keystone.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * Keystone broadcast clock-event | ||
3 | * | ||
4 | * Copyright 2013 Texas Instruments, Inc. | ||
5 | * | ||
6 | * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/clockchips.h> | ||
16 | #include <linux/clocksource.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/of_irq.h> | ||
20 | |||
21 | #define TIMER_NAME "timer-keystone" | ||
22 | |||
23 | /* Timer register offsets */ | ||
24 | #define TIM12 0x10 | ||
25 | #define TIM34 0x14 | ||
26 | #define PRD12 0x18 | ||
27 | #define PRD34 0x1c | ||
28 | #define TCR 0x20 | ||
29 | #define TGCR 0x24 | ||
30 | #define INTCTLSTAT 0x44 | ||
31 | |||
32 | /* Timer register bitfields */ | ||
33 | #define TCR_ENAMODE_MASK 0xC0 | ||
34 | #define TCR_ENAMODE_ONESHOT_MASK 0x40 | ||
35 | #define TCR_ENAMODE_PERIODIC_MASK 0x80 | ||
36 | |||
37 | #define TGCR_TIM_UNRESET_MASK 0x03 | ||
38 | #define INTCTLSTAT_ENINT_MASK 0x01 | ||
39 | |||
40 | /** | ||
41 | * struct keystone_timer: holds timer's data | ||
42 | * @base: timer memory base address | ||
43 | * @hz_period: cycles per HZ period | ||
44 | * @event_dev: event device based on timer | ||
45 | */ | ||
46 | static struct keystone_timer { | ||
47 | void __iomem *base; | ||
48 | unsigned long hz_period; | ||
49 | struct clock_event_device event_dev; | ||
50 | } timer; | ||
51 | |||
52 | static inline u32 keystone_timer_readl(unsigned long rg) | ||
53 | { | ||
54 | return readl_relaxed(timer.base + rg); | ||
55 | } | ||
56 | |||
57 | static inline void keystone_timer_writel(u32 val, unsigned long rg) | ||
58 | { | ||
59 | writel_relaxed(val, timer.base + rg); | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * keystone_timer_barrier: write memory barrier | ||
64 | * use explicit barrier to avoid using readl/writel non relaxed function | ||
65 | * variants, because in our case non relaxed variants hide the true places | ||
66 | * where barrier is needed. | ||
67 | */ | ||
68 | static inline void keystone_timer_barrier(void) | ||
69 | { | ||
70 | __iowmb(); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * keystone_timer_config: configures timer to work in oneshot/periodic modes. | ||
75 | * @ mode: mode to configure | ||
76 | * @ period: cycles number to configure for | ||
77 | */ | ||
78 | static int keystone_timer_config(u64 period, enum clock_event_mode mode) | ||
79 | { | ||
80 | u32 tcr; | ||
81 | u32 off; | ||
82 | |||
83 | tcr = keystone_timer_readl(TCR); | ||
84 | off = tcr & ~(TCR_ENAMODE_MASK); | ||
85 | |||
86 | /* set enable mode */ | ||
87 | switch (mode) { | ||
88 | case CLOCK_EVT_MODE_ONESHOT: | ||
89 | tcr |= TCR_ENAMODE_ONESHOT_MASK; | ||
90 | break; | ||
91 | case CLOCK_EVT_MODE_PERIODIC: | ||
92 | tcr |= TCR_ENAMODE_PERIODIC_MASK; | ||
93 | break; | ||
94 | default: | ||
95 | return -1; | ||
96 | } | ||
97 | |||
98 | /* disable timer */ | ||
99 | keystone_timer_writel(off, TCR); | ||
100 | /* here we have to be sure the timer has been disabled */ | ||
101 | keystone_timer_barrier(); | ||
102 | |||
103 | /* reset counter to zero, set new period */ | ||
104 | keystone_timer_writel(0, TIM12); | ||
105 | keystone_timer_writel(0, TIM34); | ||
106 | keystone_timer_writel(period & 0xffffffff, PRD12); | ||
107 | keystone_timer_writel(period >> 32, PRD34); | ||
108 | |||
109 | /* | ||
110 | * enable timer | ||
111 | * here we have to be sure that CNTLO, CNTHI, PRDLO, PRDHI registers | ||
112 | * have been written. | ||
113 | */ | ||
114 | keystone_timer_barrier(); | ||
115 | keystone_timer_writel(tcr, TCR); | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static void keystone_timer_disable(void) | ||
120 | { | ||
121 | u32 tcr; | ||
122 | |||
123 | tcr = keystone_timer_readl(TCR); | ||
124 | |||
125 | /* disable timer */ | ||
126 | tcr &= ~(TCR_ENAMODE_MASK); | ||
127 | keystone_timer_writel(tcr, TCR); | ||
128 | } | ||
129 | |||
130 | static irqreturn_t keystone_timer_interrupt(int irq, void *dev_id) | ||
131 | { | ||
132 | struct clock_event_device *evt = dev_id; | ||
133 | |||
134 | evt->event_handler(evt); | ||
135 | return IRQ_HANDLED; | ||
136 | } | ||
137 | |||
138 | static int keystone_set_next_event(unsigned long cycles, | ||
139 | struct clock_event_device *evt) | ||
140 | { | ||
141 | return keystone_timer_config(cycles, evt->mode); | ||
142 | } | ||
143 | |||
144 | static void keystone_set_mode(enum clock_event_mode mode, | ||
145 | struct clock_event_device *evt) | ||
146 | { | ||
147 | switch (mode) { | ||
148 | case CLOCK_EVT_MODE_PERIODIC: | ||
149 | keystone_timer_config(timer.hz_period, CLOCK_EVT_MODE_PERIODIC); | ||
150 | break; | ||
151 | case CLOCK_EVT_MODE_UNUSED: | ||
152 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
153 | case CLOCK_EVT_MODE_ONESHOT: | ||
154 | keystone_timer_disable(); | ||
155 | break; | ||
156 | default: | ||
157 | break; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | static void __init keystone_timer_init(struct device_node *np) | ||
162 | { | ||
163 | struct clock_event_device *event_dev = &timer.event_dev; | ||
164 | unsigned long rate; | ||
165 | struct clk *clk; | ||
166 | int irq, error; | ||
167 | |||
168 | irq = irq_of_parse_and_map(np, 0); | ||
169 | if (irq == NO_IRQ) { | ||
170 | pr_err("%s: failed to map interrupts\n", __func__); | ||
171 | return; | ||
172 | } | ||
173 | |||
174 | timer.base = of_iomap(np, 0); | ||
175 | if (!timer.base) { | ||
176 | pr_err("%s: failed to map registers\n", __func__); | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | clk = of_clk_get(np, 0); | ||
181 | if (IS_ERR(clk)) { | ||
182 | pr_err("%s: failed to get clock\n", __func__); | ||
183 | iounmap(timer.base); | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | error = clk_prepare_enable(clk); | ||
188 | if (error) { | ||
189 | pr_err("%s: failed to enable clock\n", __func__); | ||
190 | goto err; | ||
191 | } | ||
192 | |||
193 | rate = clk_get_rate(clk); | ||
194 | |||
195 | /* disable, use internal clock source */ | ||
196 | keystone_timer_writel(0, TCR); | ||
197 | /* here we have to be sure the timer has been disabled */ | ||
198 | keystone_timer_barrier(); | ||
199 | |||
200 | /* reset timer as 64-bit, no pre-scaler, plus features are disabled */ | ||
201 | keystone_timer_writel(0, TGCR); | ||
202 | |||
203 | /* unreset timer */ | ||
204 | keystone_timer_writel(TGCR_TIM_UNRESET_MASK, TGCR); | ||
205 | |||
206 | /* init counter to zero */ | ||
207 | keystone_timer_writel(0, TIM12); | ||
208 | keystone_timer_writel(0, TIM34); | ||
209 | |||
210 | timer.hz_period = DIV_ROUND_UP(rate, HZ); | ||
211 | |||
212 | /* enable timer interrupts */ | ||
213 | keystone_timer_writel(INTCTLSTAT_ENINT_MASK, INTCTLSTAT); | ||
214 | |||
215 | error = request_irq(irq, keystone_timer_interrupt, IRQF_TIMER, | ||
216 | TIMER_NAME, event_dev); | ||
217 | if (error) { | ||
218 | pr_err("%s: failed to setup irq\n", __func__); | ||
219 | goto err; | ||
220 | } | ||
221 | |||
222 | /* setup clockevent */ | ||
223 | event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | ||
224 | event_dev->set_next_event = keystone_set_next_event; | ||
225 | event_dev->set_mode = keystone_set_mode; | ||
226 | event_dev->cpumask = cpu_all_mask; | ||
227 | event_dev->owner = THIS_MODULE; | ||
228 | event_dev->name = TIMER_NAME; | ||
229 | event_dev->irq = irq; | ||
230 | |||
231 | clockevents_config_and_register(event_dev, rate, 1, ULONG_MAX); | ||
232 | |||
233 | pr_info("keystone timer clock @%lu Hz\n", rate); | ||
234 | return; | ||
235 | err: | ||
236 | clk_put(clk); | ||
237 | iounmap(timer.base); | ||
238 | } | ||
239 | |||
240 | CLOCKSOURCE_OF_DECLARE(keystone_timer, "ti,keystone-timer", | ||
241 | keystone_timer_init); | ||