1/*
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	p->pdev = pdev;
157
158	res[REG_CH] = platform_get_resource(p->pdev,
159					    IORESOURCE_MEM, REG_CH);
160	res[REG_COMM] = platform_get_resource(p->pdev,
161					      IORESOURCE_MEM, REG_COMM);
162	if (!res[REG_CH] || !res[REG_COMM]) {
163		dev_err(&p->pdev->dev, "failed to get I/O memory\n");
164		return -ENXIO;
165	}
166	irq = platform_get_irq(p->pdev, 0);
167	if (irq < 0) {
168		dev_err(&p->pdev->dev, "failed to get irq\n");
169		return irq;
170	}
171
172	p->clk = clk_get(&p->pdev->dev, "fck");
173	if (IS_ERR(p->clk)) {
174		dev_err(&p->pdev->dev, "can't get clk\n");
175		return PTR_ERR(p->clk);
176	}
177	of_property_read_u32(p->pdev->dev.of_node, "renesas,channel", &ch);
178
179	p->pdev = pdev;
180	p->mapbase = res[REG_CH]->start;
181	p->mapcommon = res[REG_COMM]->start;
182	p->enb = 1 << ch;
183	p->imfa = 1 << ch;
184	p->imiea = 1 << (4 + ch);
185	p->cs.name = pdev->name;
186	p->cs.rating = 200;
187	p->cs.read = timer16_clocksource_read;
188	p->cs.enable = timer16_enable;
189	p->cs.disable = timer16_disable;
190	p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
191	p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
192
193	ret = request_irq(irq, timer16_interrupt,
194			  IRQF_TIMER, pdev->name, p);
195	if (ret < 0) {
196		dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
197		return ret;
198	}
199
200	clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 8);
201
202	return 0;
203}
204
205static int timer16_probe(struct platform_device *pdev)
206{
207	struct timer16_priv *p = platform_get_drvdata(pdev);
208
209	if (p) {
210		dev_info(&pdev->dev, "kept as earlytimer\n");
211		return 0;
212	}
213
214	p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
215	if (!p)
216		return -ENOMEM;
217
218	return timer16_setup(p, pdev);
219}
220
221static int timer16_remove(struct platform_device *pdev)
222{
223	return -EBUSY;
224}
225
226static const struct of_device_id timer16_of_table[] = {
227	{ .compatible = "renesas,16bit-timer" },
228	{ }
229};
230static struct platform_driver timer16_driver = {
231	.probe		= timer16_probe,
232	.remove		= timer16_remove,
233	.driver		= {
234		.name	= "h8300h-16timer",
235		.of_match_table = of_match_ptr(timer16_of_table),
236	}
237};
238
239static int __init timer16_init(void)
240{
241	return platform_driver_register(&timer16_driver);
242}
243
244static void __exit timer16_exit(void)
245{
246	platform_driver_unregister(&timer16_driver);
247}
248
249subsys_initcall(timer16_init);
250module_exit(timer16_exit);
251MODULE_AUTHOR("Yoshinori Sato");
252MODULE_DESCRIPTION("H8/300H 16bit Timer Driver");
253MODULE_LICENSE("GPL v2");
254