1d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm/*
2d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * SuperH Timer Support - MTU2
3d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm *
4d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm *  Copyright (C) 2009 Magnus Damm
5d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm *
6d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * This program is free software; you can redistribute it and/or modify
7d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * it under the terms of the GNU General Public License as published by
8d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * the Free Software Foundation; either version 2 of the License
9d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm *
10d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * This program is distributed in the hope that it will be useful,
11d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * but WITHOUT ANY WARRANTY; without even the implied warranty of
12d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * GNU General Public License for more details.
14d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm *
15d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * You should have received a copy of the GNU General Public License
16d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * along with this program; if not, write to the Free Software
17d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm */
19d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
20d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/init.h>
21d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/platform_device.h>
22d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/spinlock.h>
23d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/interrupt.h>
24d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/ioport.h>
25d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/delay.h>
26d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/io.h>
27d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/clk.h>
28d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/irq.h>
29d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/err.h>
30d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/clockchips.h>
3146a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt#include <linux/sh_timer.h>
325a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
337deeab5dc414240a341e80f41b5f00620aa9ef98Paul Gortmaker#include <linux/module.h>
3457d13370cfaf6017c68981e66ff5b3bf20a2705cRafael J. Wysocki#include <linux/pm_domain.h>
35d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
36d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstruct sh_mtu2_priv {
37d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	void __iomem *mapbase;
38d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	struct clk *clk;
39d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	struct irqaction irqaction;
40d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	struct platform_device *pdev;
41d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	unsigned long rate;
42d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	unsigned long periodic;
43d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	struct clock_event_device ced;
44d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm};
45d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
46d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic DEFINE_SPINLOCK(sh_mtu2_lock);
47d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
48d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TSTR -1 /* shared register */
49d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TCR  0 /* channel register */
50d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TMDR 1 /* channel register */
51d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TIOR 2 /* channel register */
52d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TIER 3 /* channel register */
53d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TSR  4 /* channel register */
54d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TCNT 5 /* channel register */
55d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TGR  6 /* channel register */
56d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
57d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic unsigned long mtu2_reg_offs[] = {
58d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	[TCR] = 0,
59d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	[TMDR] = 1,
60d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	[TIOR] = 2,
61d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	[TIER] = 4,
62d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	[TSR] = 5,
63d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	[TCNT] = 6,
64d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	[TGR] = 8,
65d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm};
66d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
67d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic inline unsigned long sh_mtu2_read(struct sh_mtu2_priv *p, int reg_nr)
68d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
6946a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt	struct sh_timer_config *cfg = p->pdev->dev.platform_data;
70d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	void __iomem *base = p->mapbase;
71d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	unsigned long offs;
72d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
73d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (reg_nr == TSTR)
74d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		return ioread8(base + cfg->channel_offset);
75d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
76d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	offs = mtu2_reg_offs[reg_nr];
77d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
78d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if ((reg_nr == TCNT) || (reg_nr == TGR))
79d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		return ioread16(base + offs);
80d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	else
81d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		return ioread8(base + offs);
82d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
83d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
84d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic inline void sh_mtu2_write(struct sh_mtu2_priv *p, int reg_nr,
85d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm				unsigned long value)
86d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
8746a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt	struct sh_timer_config *cfg = p->pdev->dev.platform_data;
88d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	void __iomem *base = p->mapbase;
89d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	unsigned long offs;
90d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
91d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (reg_nr == TSTR) {
92d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		iowrite8(value, base + cfg->channel_offset);
93d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		return;
94d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
95d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
96d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	offs = mtu2_reg_offs[reg_nr];
97d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
98d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if ((reg_nr == TCNT) || (reg_nr == TGR))
99d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		iowrite16(value, base + offs);
100d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	else
101d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		iowrite8(value, base + offs);
102d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
103d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
104d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic void sh_mtu2_start_stop_ch(struct sh_mtu2_priv *p, int start)
105d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
10646a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt	struct sh_timer_config *cfg = p->pdev->dev.platform_data;
107d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	unsigned long flags, value;
108d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
109d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* start stop register shared by multiple timer channels */
110d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	spin_lock_irqsave(&sh_mtu2_lock, flags);
111d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	value = sh_mtu2_read(p, TSTR);
112d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
113d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (start)
114d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		value |= 1 << cfg->timer_bit;
115d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	else
116d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		value &= ~(1 << cfg->timer_bit);
117d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
118d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_write(p, TSTR, value);
119d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	spin_unlock_irqrestore(&sh_mtu2_lock, flags);
120d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
121d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
122d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic int sh_mtu2_enable(struct sh_mtu2_priv *p)
123d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
124d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	int ret;
125d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
126d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* enable clock */
127d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	ret = clk_enable(p->clk);
128d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (ret) {
129214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt		dev_err(&p->pdev->dev, "cannot enable clock\n");
130d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		return ret;
131d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
132d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
133d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* make sure channel is disabled */
134d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_start_stop_ch(p, 0);
135d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
136d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	p->rate = clk_get_rate(p->clk) / 64;
137d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	p->periodic = (p->rate + HZ/2) / HZ;
138d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
139d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* "Periodic Counter Operation" */
140d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_write(p, TCR, 0x23); /* TGRA clear, divide clock by 64 */
141d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_write(p, TIOR, 0);
142d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_write(p, TGR, p->periodic);
143d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_write(p, TCNT, 0);
144d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_write(p, TMDR, 0);
145d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_write(p, TIER, 0x01);
146d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
147d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* enable channel */
148d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_start_stop_ch(p, 1);
149d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
150d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	return 0;
151d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
152d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
153d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic void sh_mtu2_disable(struct sh_mtu2_priv *p)
154d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
155d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* disable channel */
156d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_start_stop_ch(p, 0);
157d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
158d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* stop clock */
159d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	clk_disable(p->clk);
160d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
161d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
162d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id)
163d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
164d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	struct sh_mtu2_priv *p = dev_id;
165d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
166d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* acknowledge interrupt */
167d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_read(p, TSR);
168d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	sh_mtu2_write(p, TSR, 0xfe);
169d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
170d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* notify clockevent layer */
171d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	p->ced.event_handler(&p->ced);
172d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	return IRQ_HANDLED;
173d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
174d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
175d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic struct sh_mtu2_priv *ced_to_sh_mtu2(struct clock_event_device *ced)
176d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
177d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	return container_of(ced, struct sh_mtu2_priv, ced);
178d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
179d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
180d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic void sh_mtu2_clock_event_mode(enum clock_event_mode mode,
181d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm				    struct clock_event_device *ced)
182d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
183d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	struct sh_mtu2_priv *p = ced_to_sh_mtu2(ced);
184d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	int disabled = 0;
185d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
186d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* deal with old setting first */
187d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	switch (ced->mode) {
188d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	case CLOCK_EVT_MODE_PERIODIC:
189d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		sh_mtu2_disable(p);
190d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		disabled = 1;
191d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		break;
192d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	default:
193d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		break;
194d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
195d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
196d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	switch (mode) {
197d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	case CLOCK_EVT_MODE_PERIODIC:
198214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt		dev_info(&p->pdev->dev, "used for periodic clock events\n");
199d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		sh_mtu2_enable(p);
200d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		break;
201d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	case CLOCK_EVT_MODE_UNUSED:
202d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		if (!disabled)
203d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm			sh_mtu2_disable(p);
204d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		break;
205d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	case CLOCK_EVT_MODE_SHUTDOWN:
206d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	default:
207d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		break;
208d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
209d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
210d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
211d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p,
212d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm				       char *name, unsigned long rating)
213d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
214d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	struct clock_event_device *ced = &p->ced;
215d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	int ret;
216d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
217d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	memset(ced, 0, sizeof(*ced));
218d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
219d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	ced->name = name;
220d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	ced->features = CLOCK_EVT_FEAT_PERIODIC;
221d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	ced->rating = rating;
222d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	ced->cpumask = cpumask_of(0);
223d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	ced->set_mode = sh_mtu2_clock_event_mode;
224d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
225214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt	dev_info(&p->pdev->dev, "used for clock events\n");
226da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt	clockevents_register_device(ced);
227da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt
228d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	ret = setup_irq(p->irqaction.irq, &p->irqaction);
229d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (ret) {
230214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt		dev_err(&p->pdev->dev, "failed to request irq %d\n",
231214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt			p->irqaction.irq);
232d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		return;
233d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
234d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
235d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
236d1fcc0a8db5e47c1abaa783a3e83dbf5f2184969Paul Mundtstatic int sh_mtu2_register(struct sh_mtu2_priv *p, char *name,
237d1fcc0a8db5e47c1abaa783a3e83dbf5f2184969Paul Mundt			    unsigned long clockevent_rating)
238d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
239d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (clockevent_rating)
240d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		sh_mtu2_register_clockevent(p, name, clockevent_rating);
241d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
242d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	return 0;
243d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
244d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
245d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
246d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
24746a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt	struct sh_timer_config *cfg = pdev->dev.platform_data;
248d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	struct resource *res;
249d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	int irq, ret;
250d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	ret = -ENXIO;
251d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
252d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	memset(p, 0, sizeof(*p));
253d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	p->pdev = pdev;
254d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
255d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (!cfg) {
256d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		dev_err(&p->pdev->dev, "missing platform data\n");
257d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		goto err0;
258d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
259d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
260d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	platform_set_drvdata(pdev, p);
261d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
262d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
263d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (!res) {
264d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		dev_err(&p->pdev->dev, "failed to get I/O memory\n");
265d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		goto err0;
266d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
267d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
268d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	irq = platform_get_irq(p->pdev, 0);
269d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (irq < 0) {
270d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		dev_err(&p->pdev->dev, "failed to get irq\n");
271d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		goto err0;
272d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
273d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
274d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* map memory, let mapbase point to our channel */
275d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	p->mapbase = ioremap_nocache(res->start, resource_size(res));
276d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (p->mapbase == NULL) {
277214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt		dev_err(&p->pdev->dev, "failed to remap I/O memory\n");
278d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		goto err0;
279d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
280d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
281d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* setup data for setup_irq() (too early for request_irq()) */
282214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt	p->irqaction.name = dev_name(&p->pdev->dev);
283d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	p->irqaction.handler = sh_mtu2_interrupt;
284d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	p->irqaction.dev_id = p;
285d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	p->irqaction.irq = irq;
286fecf066c2d2fbc7e6a7e7e3a5af772a165bdd7b0Paul Mundt	p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \
287fecf066c2d2fbc7e6a7e7e3a5af772a165bdd7b0Paul Mundt			     IRQF_IRQPOLL  | IRQF_NOBALANCING;
288d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
289d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	/* get hold of clock */
290c2a25e819717ea34e8f682d67a3fa76f4893395bPaul Mundt	p->clk = clk_get(&p->pdev->dev, "mtu2_fck");
291d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (IS_ERR(p->clk)) {
29203ff858c09c81a659b2a90a08826bc0abdbb784cMagnus Damm		dev_err(&p->pdev->dev, "cannot get clock\n");
29303ff858c09c81a659b2a90a08826bc0abdbb784cMagnus Damm		ret = PTR_ERR(p->clk);
29403ff858c09c81a659b2a90a08826bc0abdbb784cMagnus Damm		goto err1;
295d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
296d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
297214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt	return sh_mtu2_register(p, (char *)dev_name(&p->pdev->dev),
298214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt				cfg->clockevent_rating);
299d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm err1:
300d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	iounmap(p->mapbase);
301d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm err0:
302d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	return ret;
303d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
304d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
305d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic int __devinit sh_mtu2_probe(struct platform_device *pdev)
306d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
307d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	struct sh_mtu2_priv *p = platform_get_drvdata(pdev);
308d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	int ret;
30957d13370cfaf6017c68981e66ff5b3bf20a2705cRafael J. Wysocki
31057d13370cfaf6017c68981e66ff5b3bf20a2705cRafael J. Wysocki	if (!is_early_platform_device(pdev))
31157d13370cfaf6017c68981e66ff5b3bf20a2705cRafael J. Wysocki		pm_genpd_dev_always_on(&pdev->dev, true);
312d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
313d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (p) {
314214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt		dev_info(&pdev->dev, "kept as earlytimer\n");
315d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		return 0;
316d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
317d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
318d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	p = kmalloc(sizeof(*p), GFP_KERNEL);
319d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (p == NULL) {
320d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		dev_err(&pdev->dev, "failed to allocate driver data\n");
321d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		return -ENOMEM;
322d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
323d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
324d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	ret = sh_mtu2_setup(p, pdev);
325d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	if (ret) {
326d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		kfree(p);
327d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		platform_set_drvdata(pdev, NULL);
328d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
329d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	return ret;
330d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
331d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
332d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic int __devexit sh_mtu2_remove(struct platform_device *pdev)
333d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
334d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	return -EBUSY; /* cannot unregister clockevent */
335d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
336d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
337d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic struct platform_driver sh_mtu2_device_driver = {
338d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	.probe		= sh_mtu2_probe,
339d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	.remove		= __devexit_p(sh_mtu2_remove),
340d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	.driver		= {
341d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm		.name	= "sh_mtu2",
342d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	}
343d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm};
344d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
345d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic int __init sh_mtu2_init(void)
346d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
347d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	return platform_driver_register(&sh_mtu2_device_driver);
348d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
349d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
350d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic void __exit sh_mtu2_exit(void)
351d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{
352d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm	platform_driver_unregister(&sh_mtu2_device_driver);
353d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}
354d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
355d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammearly_platform_init("earlytimer", &sh_mtu2_device_driver);
356d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammmodule_init(sh_mtu2_init);
357d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammmodule_exit(sh_mtu2_exit);
358d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm
359d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus DammMODULE_AUTHOR("Magnus Damm");
360d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus DammMODULE_DESCRIPTION("SuperH MTU2 Timer Driver");
361d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus DammMODULE_LICENSE("GPL v2");
362