• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/clocksource/
1/*
2 * SuperH Timer Support - TMU
3 *
4 *  Copyright (C) 2009 Magnus Damm
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20#include <linux/init.h>
21#include <linux/platform_device.h>
22#include <linux/spinlock.h>
23#include <linux/interrupt.h>
24#include <linux/ioport.h>
25#include <linux/delay.h>
26#include <linux/io.h>
27#include <linux/clk.h>
28#include <linux/irq.h>
29#include <linux/err.h>
30#include <linux/clocksource.h>
31#include <linux/clockchips.h>
32#include <linux/sh_timer.h>
33#include <linux/slab.h>
34
35struct sh_tmu_priv {
36	void __iomem *mapbase;
37	struct clk *clk;
38	struct irqaction irqaction;
39	struct platform_device *pdev;
40	unsigned long rate;
41	unsigned long periodic;
42	struct clock_event_device ced;
43	struct clocksource cs;
44};
45
46static DEFINE_SPINLOCK(sh_tmu_lock);
47
48#define TSTR -1 /* shared register */
49#define TCOR  0 /* channel register */
50#define TCNT 1 /* channel register */
51#define TCR 2 /* channel register */
52
53static inline unsigned long sh_tmu_read(struct sh_tmu_priv *p, int reg_nr)
54{
55	struct sh_timer_config *cfg = p->pdev->dev.platform_data;
56	void __iomem *base = p->mapbase;
57	unsigned long offs;
58
59	if (reg_nr == TSTR)
60		return ioread8(base - cfg->channel_offset);
61
62	offs = reg_nr << 2;
63
64	if (reg_nr == TCR)
65		return ioread16(base + offs);
66	else
67		return ioread32(base + offs);
68}
69
70static inline void sh_tmu_write(struct sh_tmu_priv *p, int reg_nr,
71				unsigned long value)
72{
73	struct sh_timer_config *cfg = p->pdev->dev.platform_data;
74	void __iomem *base = p->mapbase;
75	unsigned long offs;
76
77	if (reg_nr == TSTR) {
78		iowrite8(value, base - cfg->channel_offset);
79		return;
80	}
81
82	offs = reg_nr << 2;
83
84	if (reg_nr == TCR)
85		iowrite16(value, base + offs);
86	else
87		iowrite32(value, base + offs);
88}
89
90static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start)
91{
92	struct sh_timer_config *cfg = p->pdev->dev.platform_data;
93	unsigned long flags, value;
94
95	/* start stop register shared by multiple timer channels */
96	spin_lock_irqsave(&sh_tmu_lock, flags);
97	value = sh_tmu_read(p, TSTR);
98
99	if (start)
100		value |= 1 << cfg->timer_bit;
101	else
102		value &= ~(1 << cfg->timer_bit);
103
104	sh_tmu_write(p, TSTR, value);
105	spin_unlock_irqrestore(&sh_tmu_lock, flags);
106}
107
108static int sh_tmu_enable(struct sh_tmu_priv *p)
109{
110	int ret;
111
112	/* enable clock */
113	ret = clk_enable(p->clk);
114	if (ret) {
115		dev_err(&p->pdev->dev, "cannot enable clock\n");
116		return ret;
117	}
118
119	/* make sure channel is disabled */
120	sh_tmu_start_stop_ch(p, 0);
121
122	/* maximum timeout */
123	sh_tmu_write(p, TCOR, 0xffffffff);
124	sh_tmu_write(p, TCNT, 0xffffffff);
125
126	/* configure channel to parent clock / 4, irq off */
127	p->rate = clk_get_rate(p->clk) / 4;
128	sh_tmu_write(p, TCR, 0x0000);
129
130	/* enable channel */
131	sh_tmu_start_stop_ch(p, 1);
132
133	return 0;
134}
135
136static void sh_tmu_disable(struct sh_tmu_priv *p)
137{
138	/* disable channel */
139	sh_tmu_start_stop_ch(p, 0);
140
141	/* disable interrupts in TMU block */
142	sh_tmu_write(p, TCR, 0x0000);
143
144	/* stop clock */
145	clk_disable(p->clk);
146}
147
148static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
149			    int periodic)
150{
151	/* stop timer */
152	sh_tmu_start_stop_ch(p, 0);
153
154	/* acknowledge interrupt */
155	sh_tmu_read(p, TCR);
156
157	/* enable interrupt */
158	sh_tmu_write(p, TCR, 0x0020);
159
160	/* reload delta value in case of periodic timer */
161	if (periodic)
162		sh_tmu_write(p, TCOR, delta);
163	else
164		sh_tmu_write(p, TCOR, 0xffffffff);
165
166	sh_tmu_write(p, TCNT, delta);
167
168	/* start timer */
169	sh_tmu_start_stop_ch(p, 1);
170}
171
172static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id)
173{
174	struct sh_tmu_priv *p = dev_id;
175
176	/* disable or acknowledge interrupt */
177	if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT)
178		sh_tmu_write(p, TCR, 0x0000);
179	else
180		sh_tmu_write(p, TCR, 0x0020);
181
182	/* notify clockevent layer */
183	p->ced.event_handler(&p->ced);
184	return IRQ_HANDLED;
185}
186
187static struct sh_tmu_priv *cs_to_sh_tmu(struct clocksource *cs)
188{
189	return container_of(cs, struct sh_tmu_priv, cs);
190}
191
192static cycle_t sh_tmu_clocksource_read(struct clocksource *cs)
193{
194	struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
195
196	return sh_tmu_read(p, TCNT) ^ 0xffffffff;
197}
198
199static int sh_tmu_clocksource_enable(struct clocksource *cs)
200{
201	struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
202
203	return sh_tmu_enable(p);
204}
205
206static void sh_tmu_clocksource_disable(struct clocksource *cs)
207{
208	sh_tmu_disable(cs_to_sh_tmu(cs));
209}
210
211static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
212				       char *name, unsigned long rating)
213{
214	struct clocksource *cs = &p->cs;
215
216	cs->name = name;
217	cs->rating = rating;
218	cs->read = sh_tmu_clocksource_read;
219	cs->enable = sh_tmu_clocksource_enable;
220	cs->disable = sh_tmu_clocksource_disable;
221	cs->mask = CLOCKSOURCE_MASK(32);
222	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
223
224	/* clk_get_rate() needs an enabled clock */
225	clk_enable(p->clk);
226	/* channel will be configured at parent clock / 4 */
227	p->rate = clk_get_rate(p->clk) / 4;
228	clk_disable(p->clk);
229	/* TODO: calculate good shift from rate and counter bit width */
230	cs->shift = 10;
231	cs->mult = clocksource_hz2mult(p->rate, cs->shift);
232
233	dev_info(&p->pdev->dev, "used as clock source\n");
234	clocksource_register(cs);
235	return 0;
236}
237
238static struct sh_tmu_priv *ced_to_sh_tmu(struct clock_event_device *ced)
239{
240	return container_of(ced, struct sh_tmu_priv, ced);
241}
242
243static void sh_tmu_clock_event_start(struct sh_tmu_priv *p, int periodic)
244{
245	struct clock_event_device *ced = &p->ced;
246
247	sh_tmu_enable(p);
248
249	/* TODO: calculate good shift from rate and counter bit width */
250
251	ced->shift = 32;
252	ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift);
253	ced->max_delta_ns = clockevent_delta2ns(0xffffffff, ced);
254	ced->min_delta_ns = 5000;
255
256	if (periodic) {
257		p->periodic = (p->rate + HZ/2) / HZ;
258		sh_tmu_set_next(p, p->periodic, 1);
259	}
260}
261
262static void sh_tmu_clock_event_mode(enum clock_event_mode mode,
263				    struct clock_event_device *ced)
264{
265	struct sh_tmu_priv *p = ced_to_sh_tmu(ced);
266	int disabled = 0;
267
268	/* deal with old setting first */
269	switch (ced->mode) {
270	case CLOCK_EVT_MODE_PERIODIC:
271	case CLOCK_EVT_MODE_ONESHOT:
272		sh_tmu_disable(p);
273		disabled = 1;
274		break;
275	default:
276		break;
277	}
278
279	switch (mode) {
280	case CLOCK_EVT_MODE_PERIODIC:
281		dev_info(&p->pdev->dev, "used for periodic clock events\n");
282		sh_tmu_clock_event_start(p, 1);
283		break;
284	case CLOCK_EVT_MODE_ONESHOT:
285		dev_info(&p->pdev->dev, "used for oneshot clock events\n");
286		sh_tmu_clock_event_start(p, 0);
287		break;
288	case CLOCK_EVT_MODE_UNUSED:
289		if (!disabled)
290			sh_tmu_disable(p);
291		break;
292	case CLOCK_EVT_MODE_SHUTDOWN:
293	default:
294		break;
295	}
296}
297
298static int sh_tmu_clock_event_next(unsigned long delta,
299				   struct clock_event_device *ced)
300{
301	struct sh_tmu_priv *p = ced_to_sh_tmu(ced);
302
303	BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
304
305	/* program new delta value */
306	sh_tmu_set_next(p, delta, 0);
307	return 0;
308}
309
310static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
311				       char *name, unsigned long rating)
312{
313	struct clock_event_device *ced = &p->ced;
314	int ret;
315
316	memset(ced, 0, sizeof(*ced));
317
318	ced->name = name;
319	ced->features = CLOCK_EVT_FEAT_PERIODIC;
320	ced->features |= CLOCK_EVT_FEAT_ONESHOT;
321	ced->rating = rating;
322	ced->cpumask = cpumask_of(0);
323	ced->set_next_event = sh_tmu_clock_event_next;
324	ced->set_mode = sh_tmu_clock_event_mode;
325
326	dev_info(&p->pdev->dev, "used for clock events\n");
327	clockevents_register_device(ced);
328
329	ret = setup_irq(p->irqaction.irq, &p->irqaction);
330	if (ret) {
331		dev_err(&p->pdev->dev, "failed to request irq %d\n",
332			p->irqaction.irq);
333		return;
334	}
335}
336
337static int sh_tmu_register(struct sh_tmu_priv *p, char *name,
338		    unsigned long clockevent_rating,
339		    unsigned long clocksource_rating)
340{
341	if (clockevent_rating)
342		sh_tmu_register_clockevent(p, name, clockevent_rating);
343	else if (clocksource_rating)
344		sh_tmu_register_clocksource(p, name, clocksource_rating);
345
346	return 0;
347}
348
349static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
350{
351	struct sh_timer_config *cfg = pdev->dev.platform_data;
352	struct resource *res;
353	int irq, ret;
354	ret = -ENXIO;
355
356	memset(p, 0, sizeof(*p));
357	p->pdev = pdev;
358
359	if (!cfg) {
360		dev_err(&p->pdev->dev, "missing platform data\n");
361		goto err0;
362	}
363
364	platform_set_drvdata(pdev, p);
365
366	res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
367	if (!res) {
368		dev_err(&p->pdev->dev, "failed to get I/O memory\n");
369		goto err0;
370	}
371
372	irq = platform_get_irq(p->pdev, 0);
373	if (irq < 0) {
374		dev_err(&p->pdev->dev, "failed to get irq\n");
375		goto err0;
376	}
377
378	/* map memory, let mapbase point to our channel */
379	p->mapbase = ioremap_nocache(res->start, resource_size(res));
380	if (p->mapbase == NULL) {
381		dev_err(&p->pdev->dev, "failed to remap I/O memory\n");
382		goto err0;
383	}
384
385	/* setup data for setup_irq() (too early for request_irq()) */
386	p->irqaction.name = dev_name(&p->pdev->dev);
387	p->irqaction.handler = sh_tmu_interrupt;
388	p->irqaction.dev_id = p;
389	p->irqaction.irq = irq;
390	p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \
391			     IRQF_IRQPOLL  | IRQF_NOBALANCING;
392
393	/* get hold of clock */
394	p->clk = clk_get(&p->pdev->dev, "tmu_fck");
395	if (IS_ERR(p->clk)) {
396		dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
397		p->clk = clk_get(&p->pdev->dev, cfg->clk);
398		if (IS_ERR(p->clk)) {
399			dev_err(&p->pdev->dev, "cannot get clock\n");
400			ret = PTR_ERR(p->clk);
401			goto err1;
402		}
403	}
404
405	return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev),
406			       cfg->clockevent_rating,
407			       cfg->clocksource_rating);
408 err1:
409	iounmap(p->mapbase);
410 err0:
411	return ret;
412}
413
414static int __devinit sh_tmu_probe(struct platform_device *pdev)
415{
416	struct sh_tmu_priv *p = platform_get_drvdata(pdev);
417	int ret;
418
419	if (p) {
420		dev_info(&pdev->dev, "kept as earlytimer\n");
421		return 0;
422	}
423
424	p = kmalloc(sizeof(*p), GFP_KERNEL);
425	if (p == NULL) {
426		dev_err(&pdev->dev, "failed to allocate driver data\n");
427		return -ENOMEM;
428	}
429
430	ret = sh_tmu_setup(p, pdev);
431	if (ret) {
432		kfree(p);
433		platform_set_drvdata(pdev, NULL);
434	}
435	return ret;
436}
437
438static int __devexit sh_tmu_remove(struct platform_device *pdev)
439{
440	return -EBUSY; /* cannot unregister clockevent and clocksource */
441}
442
443static struct platform_driver sh_tmu_device_driver = {
444	.probe		= sh_tmu_probe,
445	.remove		= __devexit_p(sh_tmu_remove),
446	.driver		= {
447		.name	= "sh_tmu",
448	}
449};
450
451static int __init sh_tmu_init(void)
452{
453	return platform_driver_register(&sh_tmu_device_driver);
454}
455
456static void __exit sh_tmu_exit(void)
457{
458	platform_driver_unregister(&sh_tmu_device_driver);
459}
460
461early_platform_init("earlytimer", &sh_tmu_device_driver);
462module_init(sh_tmu_init);
463module_exit(sh_tmu_exit);
464
465MODULE_AUTHOR("Magnus Damm");
466MODULE_DESCRIPTION("SuperH TMU Timer Driver");
467MODULE_LICENSE("GPL v2");
468