blob: 3eedeffccc260d9e3bcd48ac9b965b67b1b66435 [file] [log] [blame]
Yoshinori Sato618b9022015-01-28 02:52:42 +09001/*
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>
Yoshinori Sato618b9022015-01-28 02:52:42 +090011#include <linux/kernel.h>
12#include <linux/interrupt.h>
13#include <linux/init.h>
Yoshinori Sato618b9022015-01-28 02:52:42 +090014#include <linux/clockchips.h>
Yoshinori Sato618b9022015-01-28 02:52:42 +090015#include <linux/clk.h>
16#include <linux/io.h>
17#include <linux/of.h>
Yoshinori Sato4633f4c2015-11-07 01:31:44 +090018#include <linux/of_address.h>
19#include <linux/of_irq.h>
Yoshinori Sato618b9022015-01-28 02:52:42 +090020
Yoshinori Sato618b9022015-01-28 02:52:42 +090021#define _8TCR 0
22#define _8TCSR 2
23#define TCORA 4
24#define TCORB 6
25#define _8TCNT 8
26
Yoshinori Sato618b9022015-01-28 02:52:42 +090027#define FLAG_SKIPEVENT (1 << 1)
28#define FLAG_IRQCONTEXT (1 << 2)
29#define FLAG_STARTED (1 << 3)
30
Yoshinori Sato4633f4c2015-11-07 01:31:44 +090031#define SCALE 64
32
Yoshinori Sato618b9022015-01-28 02:52:42 +090033struct timer8_priv {
Yoshinori Sato618b9022015-01-28 02:52:42 +090034 struct clock_event_device ced;
Yoshinori Sato618b9022015-01-28 02:52:42 +090035 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)) {
Viresh Kumarfc2b2f52015-07-27 15:02:00 +053073 if (clockevent_state_oneshot(&p->ced))
Yoshinori Sato618b9022015-01-28 02:52:42 +090074 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)
Daniel Lezcano8c09b7d2015-11-09 09:02:38 +010089 pr_warn("delta out of range\n");
Yoshinori Sato618b9022015-01-28 02:52:42 +090090 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{
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900103 p->rate = clk_get_rate(p->pclk) / SCALE;
Yoshinori Sato618b9022015-01-28 02:52:42 +0900104 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
Daniel Lezcano1f058d52015-11-08 17:46:54 +0100147static void timer8_clock_event_start(struct timer8_priv *p, unsigned long delta)
Yoshinori Sato618b9022015-01-28 02:52:42 +0900148{
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
Daniel Lezcano1f058d52015-11-08 17:46:54 +0100158 timer8_set_next(p, delta);
Yoshinori Sato618b9022015-01-28 02:52:42 +0900159}
160
Viresh Kumarfc2b2f52015-07-27 15:02:00 +0530161static 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)
Yoshinori Sato618b9022015-01-28 02:52:42 +0900168{
169 struct timer8_priv *p = ced_to_priv(ced);
170
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900171 pr_info("%s: used for periodic clock events\n", ced->name);
Viresh Kumarfc2b2f52015-07-27 15:02:00 +0530172 timer8_stop(p);
Daniel Lezcano1f058d52015-11-08 17:46:54 +0100173 timer8_clock_event_start(p, (p->rate + HZ/2) / HZ);
Viresh Kumarfc2b2f52015-07-27 15:02:00 +0530174
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
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900182 pr_info("%s: used for oneshot clock events\n", ced->name);
Viresh Kumarfc2b2f52015-07-27 15:02:00 +0530183 timer8_stop(p);
Daniel Lezcano1f058d52015-11-08 17:46:54 +0100184 timer8_clock_event_start(p, 0x10000);
Viresh Kumarfc2b2f52015-07-27 15:02:00 +0530185
186 return 0;
Yoshinori Sato618b9022015-01-28 02:52:42 +0900187}
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
Viresh Kumarfc2b2f52015-07-27 15:02:00 +0530194 BUG_ON(!clockevent_state_oneshot(ced));
Yoshinori Sato618b9022015-01-28 02:52:42 +0900195 timer8_set_next(p, delta - 1);
196
197 return 0;
198}
199
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900200static 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)
Yoshinori Sato618b9022015-01-28 02:52:42 +0900213{
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900214 void __iomem *base;
Yoshinori Sato618b9022015-01-28 02:52:42 +0900215 int irq;
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900216 int ret = 0;
217 int rate;
218 struct clk *clk;
Yoshinori Sato618b9022015-01-28 02:52:42 +0900219
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900220 clk = of_clk_get(node, 0);
221 if (IS_ERR(clk)) {
222 pr_err("failed to get clock for clockevent\n");
223 return;
Yoshinori Sato618b9022015-01-28 02:52:42 +0900224 }
225
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900226 base = of_iomap(node, 0);
227 if (!base) {
228 pr_err("failed to map registers for clockevent\n");
229 goto free_clk;
230 }
231
232 irq = irq_of_parse_and_map(node, 0);
Daniel Lezcano54a0cd52015-11-08 17:56:18 +0100233 if (!irq) {
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900234 pr_err("failed to get irq for clockevent\n");
235 goto unmap_reg;
Yoshinori Sato618b9022015-01-28 02:52:42 +0900236 }
237
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900238 timer8_priv.mapbase = (unsigned long)base;
239 timer8_priv.pclk = clk;
Yoshinori Sato618b9022015-01-28 02:52:42 +0900240
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900241 ret = request_irq(irq, timer8_interrupt,
242 IRQF_TIMER, timer8_priv.ced.name, &timer8_priv);
Yoshinori Sato618b9022015-01-28 02:52:42 +0900243 if (ret < 0) {
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900244 pr_err("failed to request irq %d for clockevent\n", irq);
245 goto unmap_reg;
Yoshinori Sato618b9022015-01-28 02:52:42 +0900246 }
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900247 rate = clk_get_rate(clk) / SCALE;
248 clockevents_config_and_register(&timer8_priv.ced, rate, 1, 0x0000ffff);
249 return;
Yoshinori Sato618b9022015-01-28 02:52:42 +0900250
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900251unmap_reg:
252 iounmap(base);
253free_clk:
254 clk_put(clk);
Yoshinori Sato618b9022015-01-28 02:52:42 +0900255}
256
Yoshinori Sato4633f4c2015-11-07 01:31:44 +0900257CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init);