blob: 82941c1e9e33f0d098ae4b0b7273fa263c3b9ce0 [file] [log] [blame]
Yoshinori Sato618b9022015-01-28 02:52:42 +09001/*
2 * H8/300 16bit Timer driver
3 *
4 * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
5 */
6
7#include <linux/errno.h>
8#include <linux/kernel.h>
9#include <linux/param.h>
10#include <linux/string.h>
11#include <linux/slab.h>
12#include <linux/interrupt.h>
13#include <linux/init.h>
14#include <linux/platform_device.h>
15#include <linux/clocksource.h>
16#include <linux/module.h>
17#include <linux/clk.h>
18#include <linux/io.h>
19#include <linux/of.h>
20
21#include <asm/segment.h>
22#include <asm/irq.h>
23
24#define TSTR 0
25#define TSNC 1
26#define TMDR 2
27#define TOLR 3
28#define TISRA 4
29#define TISRB 5
30#define TISRC 6
31
32#define TCR 0
33#define TIOR 1
34#define TCNT 2
35#define GRA 4
36#define GRB 6
37
38#define FLAG_REPROGRAM (1 << 0)
39#define FLAG_SKIPEVENT (1 << 1)
40#define FLAG_IRQCONTEXT (1 << 2)
41#define FLAG_STARTED (1 << 3)
42
43#define ONESHOT 0
44#define PERIODIC 1
45
46#define RELATIVE 0
47#define ABSOLUTE 1
48
49struct timer16_priv {
50 struct platform_device *pdev;
51 struct clocksource cs;
52 struct irqaction irqaction;
53 unsigned long total_cycles;
54 unsigned long mapbase;
55 unsigned long mapcommon;
56 unsigned long flags;
57 unsigned short gra;
58 unsigned short cs_enabled;
59 unsigned char enb;
60 unsigned char imfa;
61 unsigned char imiea;
62 unsigned char ovf;
63 raw_spinlock_t lock;
64 struct clk *clk;
65};
66
67static unsigned long timer16_get_counter(struct timer16_priv *p)
68{
69 unsigned long v1, v2, v3;
70 int o1, o2;
71
72 o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
73
74 /* Make sure the timer value is stable. Stolen from acpi_pm.c */
75 do {
76 o2 = o1;
77 v1 = ctrl_inw(p->mapbase + TCNT);
78 v2 = ctrl_inw(p->mapbase + TCNT);
79 v3 = ctrl_inw(p->mapbase + TCNT);
80 o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
81 } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
82 || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
83
84 v2 |= 0x10000;
85 return v2;
86}
87
88
89static irqreturn_t timer16_interrupt(int irq, void *dev_id)
90{
91 struct timer16_priv *p = (struct timer16_priv *)dev_id;
92
93 ctrl_outb(ctrl_inb(p->mapcommon + TISRA) & ~p->imfa,
94 p->mapcommon + TISRA);
95 p->total_cycles += 0x10000;
96
97 return IRQ_HANDLED;
98}
99
100static inline struct timer16_priv *cs_to_priv(struct clocksource *cs)
101{
102 return container_of(cs, struct timer16_priv, cs);
103}
104
105static cycle_t timer16_clocksource_read(struct clocksource *cs)
106{
107 struct timer16_priv *p = cs_to_priv(cs);
108 unsigned long flags, raw;
109 unsigned long value;
110
111 raw_spin_lock_irqsave(&p->lock, flags);
112 value = p->total_cycles;
113 raw = timer16_get_counter(p);
114 raw_spin_unlock_irqrestore(&p->lock, flags);
115
116 return value + raw;
117}
118
119static int timer16_enable(struct clocksource *cs)
120{
121 struct timer16_priv *p = cs_to_priv(cs);
122
123 WARN_ON(p->cs_enabled);
124
125 p->total_cycles = 0;
126 ctrl_outw(0x0000, p->mapbase + TCNT);
127 ctrl_outb(0x83, p->mapbase + TCR);
128 ctrl_outb(ctrl_inb(p->mapcommon + TSTR) | p->enb,
129 p->mapcommon + TSTR);
130
131 p->cs_enabled = true;
132 return 0;
133}
134
135static void timer16_disable(struct clocksource *cs)
136{
137 struct timer16_priv *p = cs_to_priv(cs);
138
139 WARN_ON(!p->cs_enabled);
140
141 ctrl_outb(ctrl_inb(p->mapcommon + TSTR) & ~p->enb,
142 p->mapcommon + TSTR);
143
144 p->cs_enabled = false;
145}
146
147#define REG_CH 0
148#define REG_COMM 1
149
150static int timer16_setup(struct timer16_priv *p, struct platform_device *pdev)
151{
152 struct resource *res[2];
153 int ret, irq;
154 unsigned int ch;
155
156 memset(p, 0, sizeof(*p));
157 p->pdev = pdev;
158
159 res[REG_CH] = platform_get_resource(p->pdev,
160 IORESOURCE_MEM, REG_CH);
161 res[REG_COMM] = platform_get_resource(p->pdev,
162 IORESOURCE_MEM, REG_COMM);
163 if (!res[REG_CH] || !res[REG_COMM]) {
164 dev_err(&p->pdev->dev, "failed to get I/O memory\n");
165 return -ENXIO;
166 }
167 irq = platform_get_irq(p->pdev, 0);
168 if (irq < 0) {
169 dev_err(&p->pdev->dev, "failed to get irq\n");
170 return irq;
171 }
172
173 p->clk = clk_get(&p->pdev->dev, "fck");
174 if (IS_ERR(p->clk)) {
175 dev_err(&p->pdev->dev, "can't get clk\n");
176 return PTR_ERR(p->clk);
177 }
178 of_property_read_u32(p->pdev->dev.of_node, "renesas,channel", &ch);
179
180 p->pdev = pdev;
181 p->mapbase = res[REG_CH]->start;
182 p->mapcommon = res[REG_COMM]->start;
183 p->enb = 1 << ch;
184 p->imfa = 1 << ch;
185 p->imiea = 1 << (4 + ch);
186 p->cs.name = pdev->name;
187 p->cs.rating = 200;
188 p->cs.read = timer16_clocksource_read;
189 p->cs.enable = timer16_enable;
190 p->cs.disable = timer16_disable;
191 p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
192 p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
193
194 ret = request_irq(irq, timer16_interrupt,
195 IRQF_TIMER, pdev->name, p);
196 if (ret < 0) {
197 dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
198 return ret;
199 }
200
201 clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 8);
202
203 return 0;
204}
205
206static int timer16_probe(struct platform_device *pdev)
207{
208 struct timer16_priv *p = platform_get_drvdata(pdev);
209
210 if (p) {
211 dev_info(&pdev->dev, "kept as earlytimer\n");
212 return 0;
213 }
214
215 p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
216 if (!p)
217 return -ENOMEM;
218
219 return timer16_setup(p, pdev);
220}
221
222static int timer16_remove(struct platform_device *pdev)
223{
224 return -EBUSY;
225}
226
227static const struct of_device_id timer16_of_table[] = {
228 { .compatible = "renesas,16bit-timer" },
229 { }
230};
231static struct platform_driver timer16_driver = {
232 .probe = timer16_probe,
233 .remove = timer16_remove,
234 .driver = {
235 .name = "h8300h-16timer",
236 .of_match_table = of_match_ptr(timer16_of_table),
237 }
238};
239
240static int __init timer16_init(void)
241{
242 return platform_driver_register(&timer16_driver);
243}
244
245static void __exit timer16_exit(void)
246{
247 platform_driver_unregister(&timer16_driver);
248}
249
250subsys_initcall(timer16_init);
251module_exit(timer16_exit);
252MODULE_AUTHOR("Yoshinori Sato");
253MODULE_DESCRIPTION("H8/300H 16bit Timer Driver");
254MODULE_LICENSE("GPL v2");