]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/clocksource/h8300_timer8.c
clocksource/drivers/h8300_timer8: Remove PERIODIC and ONESHOT macro
[mirror_ubuntu-artful-kernel.git] / drivers / clocksource / h8300_timer8.c
CommitLineData
618b902d
YS
1/*
2 * linux/arch/h8300/kernel/cpu/timer/timer8.c
3 *
4 * Yoshinori Sato <ysato@users.sourcefoge.jp>
5 *
6 * 8bit Timer driver
7 *
8 */
9
10#include <linux/errno.h>
618b902d
YS
11#include <linux/kernel.h>
12#include <linux/interrupt.h>
13#include <linux/init.h>
618b902d 14#include <linux/clockchips.h>
618b902d
YS
15#include <linux/clk.h>
16#include <linux/io.h>
17#include <linux/of.h>
4633f4ca
YS
18#include <linux/of_address.h>
19#include <linux/of_irq.h>
618b902d 20
618b902d
YS
21#define _8TCR 0
22#define _8TCSR 2
23#define TCORA 4
24#define TCORB 6
25#define _8TCNT 8
26
618b902d
YS
27#define FLAG_SKIPEVENT (1 << 1)
28#define FLAG_IRQCONTEXT (1 << 2)
29#define FLAG_STARTED (1 << 3)
30
4633f4ca
YS
31#define SCALE 64
32
618b902d 33struct timer8_priv {
618b902d 34 struct clock_event_device ced;
618b902d
YS
35 unsigned long mapbase;
36 raw_spinlock_t lock;
37 unsigned long flags;
38 unsigned int rate;
39 unsigned int tcora;
40 struct clk *pclk;
41};
42
43static unsigned long timer8_get_counter(struct timer8_priv *p)
44{
45 unsigned long v1, v2, v3;
46 int o1, o2;
47
48 o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
49
50 /* Make sure the timer value is stable. Stolen from acpi_pm.c */
51 do {
52 o2 = o1;
53 v1 = ctrl_inw(p->mapbase + _8TCNT);
54 v2 = ctrl_inw(p->mapbase + _8TCNT);
55 v3 = ctrl_inw(p->mapbase + _8TCNT);
56 o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
57 } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
58 || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
59
60 v2 |= o1 << 10;
61 return v2;
62}
63
64static irqreturn_t timer8_interrupt(int irq, void *dev_id)
65{
66 struct timer8_priv *p = dev_id;
67
68 ctrl_outb(ctrl_inb(p->mapbase + _8TCSR) & ~0x40,
69 p->mapbase + _8TCSR);
70 p->flags |= FLAG_IRQCONTEXT;
71 ctrl_outw(p->tcora, p->mapbase + TCORA);
72 if (!(p->flags & FLAG_SKIPEVENT)) {
fc2b2f5d 73 if (clockevent_state_oneshot(&p->ced))
618b902d
YS
74 ctrl_outw(0x0000, p->mapbase + _8TCR);
75 p->ced.event_handler(&p->ced);
76 }
77 p->flags &= ~(FLAG_SKIPEVENT | FLAG_IRQCONTEXT);
78
79 return IRQ_HANDLED;
80}
81
82static void timer8_set_next(struct timer8_priv *p, unsigned long delta)
83{
84 unsigned long flags;
85 unsigned long now;
86
87 raw_spin_lock_irqsave(&p->lock, flags);
88 if (delta >= 0x10000)
8c09b7d6 89 pr_warn("delta out of range\n");
618b902d
YS
90 now = timer8_get_counter(p);
91 p->tcora = delta;
92 ctrl_outb(ctrl_inb(p->mapbase + _8TCR) | 0x40, p->mapbase + _8TCR);
93 if (delta > now)
94 ctrl_outw(delta, p->mapbase + TCORA);
95 else
96 ctrl_outw(now + 1, p->mapbase + TCORA);
97
98 raw_spin_unlock_irqrestore(&p->lock, flags);
99}
100
101static int timer8_enable(struct timer8_priv *p)
102{
4633f4ca 103 p->rate = clk_get_rate(p->pclk) / SCALE;
618b902d
YS
104 ctrl_outw(0xffff, p->mapbase + TCORA);
105 ctrl_outw(0x0000, p->mapbase + _8TCNT);
106 ctrl_outw(0x0c02, p->mapbase + _8TCR);
107
108 return 0;
109}
110
111static int timer8_start(struct timer8_priv *p)
112{
113 int ret = 0;
114 unsigned long flags;
115
116 raw_spin_lock_irqsave(&p->lock, flags);
117
118 if (!(p->flags & FLAG_STARTED))
119 ret = timer8_enable(p);
120
121 if (ret)
122 goto out;
123 p->flags |= FLAG_STARTED;
124
125 out:
126 raw_spin_unlock_irqrestore(&p->lock, flags);
127
128 return ret;
129}
130
131static void timer8_stop(struct timer8_priv *p)
132{
133 unsigned long flags;
134
135 raw_spin_lock_irqsave(&p->lock, flags);
136
137 ctrl_outw(0x0000, p->mapbase + _8TCR);
138
139 raw_spin_unlock_irqrestore(&p->lock, flags);
140}
141
142static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
143{
144 return container_of(ced, struct timer8_priv, ced);
145}
146
1f058d52 147static void timer8_clock_event_start(struct timer8_priv *p, unsigned long delta)
618b902d
YS
148{
149 struct clock_event_device *ced = &p->ced;
150
151 timer8_start(p);
152
153 ced->shift = 32;
154 ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift);
155 ced->max_delta_ns = clockevent_delta2ns(0xffff, ced);
156 ced->min_delta_ns = clockevent_delta2ns(0x0001, ced);
157
1f058d52 158 timer8_set_next(p, delta);
618b902d
YS
159}
160
fc2b2f5d
VK
161static int timer8_clock_event_shutdown(struct clock_event_device *ced)
162{
163 timer8_stop(ced_to_priv(ced));
164 return 0;
165}
166
167static int timer8_clock_event_periodic(struct clock_event_device *ced)
618b902d
YS
168{
169 struct timer8_priv *p = ced_to_priv(ced);
170
4633f4ca 171 pr_info("%s: used for periodic clock events\n", ced->name);
fc2b2f5d 172 timer8_stop(p);
1f058d52 173 timer8_clock_event_start(p, (p->rate + HZ/2) / HZ);
fc2b2f5d
VK
174
175 return 0;
176}
177
178static int timer8_clock_event_oneshot(struct clock_event_device *ced)
179{
180 struct timer8_priv *p = ced_to_priv(ced);
181
4633f4ca 182 pr_info("%s: used for oneshot clock events\n", ced->name);
fc2b2f5d 183 timer8_stop(p);
1f058d52 184 timer8_clock_event_start(p, 0x10000);
fc2b2f5d
VK
185
186 return 0;
618b902d
YS
187}
188
189static int timer8_clock_event_next(unsigned long delta,
190 struct clock_event_device *ced)
191{
192 struct timer8_priv *p = ced_to_priv(ced);
193
fc2b2f5d 194 BUG_ON(!clockevent_state_oneshot(ced));
618b902d
YS
195 timer8_set_next(p, delta - 1);
196
197 return 0;
198}
199
4633f4ca
YS
200static struct timer8_priv timer8_priv = {
201 .ced = {
202 .name = "h8300_8timer",
203 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
204 .rating = 200,
205 .set_next_event = timer8_clock_event_next,
206 .set_state_shutdown = timer8_clock_event_shutdown,
207 .set_state_periodic = timer8_clock_event_periodic,
208 .set_state_oneshot = timer8_clock_event_oneshot,
209 },
210};
211
212static void __init h8300_8timer_init(struct device_node *node)
618b902d 213{
4633f4ca 214 void __iomem *base;
618b902d 215 int irq;
4633f4ca
YS
216 int ret = 0;
217 int rate;
218 struct clk *clk;
618b902d 219
4633f4ca
YS
220 clk = of_clk_get(node, 0);
221 if (IS_ERR(clk)) {
222 pr_err("failed to get clock for clockevent\n");
223 return;
224 }
618b902d 225
4633f4ca
YS
226 base = of_iomap(node, 0);
227 if (!base) {
228 pr_err("failed to map registers for clockevent\n");
229 goto free_clk;
618b902d
YS
230 }
231
4633f4ca 232 irq = irq_of_parse_and_map(node, 0);
618b902d 233 if (irq < 0) {
4633f4ca
YS
234 pr_err("failed to get irq for clockevent\n");
235 goto unmap_reg;
618b902d
YS
236 }
237
4633f4ca
YS
238 timer8_priv.mapbase = (unsigned long)base;
239 timer8_priv.pclk = clk;
618b902d 240
4633f4ca
YS
241 ret = request_irq(irq, timer8_interrupt,
242 IRQF_TIMER, timer8_priv.ced.name, &timer8_priv);
618b902d 243 if (ret < 0) {
4633f4ca
YS
244 pr_err("failed to request irq %d for clockevent\n", irq);
245 goto unmap_reg;
618b902d 246 }
4633f4ca
YS
247 rate = clk_get_rate(clk) / SCALE;
248 clockevents_config_and_register(&timer8_priv.ced, rate, 1, 0x0000ffff);
249 return;
250
251unmap_reg:
252 iounmap(base);
253free_clk:
254 clk_put(clk);
618b902d
YS
255}
256
4633f4ca 257CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init);