xref: /linux/drivers/clocksource/timer-imx-gpt.c (revision 1727339590fdb5a1ded881b540cd32121278d414)
1bea5af41SShawn Guo /*
2bea5af41SShawn Guo  *  linux/arch/arm/plat-mxc/time.c
3bea5af41SShawn Guo  *
4bea5af41SShawn Guo  *  Copyright (C) 2000-2001 Deep Blue Solutions
5bea5af41SShawn Guo  *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
6bea5af41SShawn Guo  *  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
7bea5af41SShawn Guo  *  Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
8bea5af41SShawn Guo  *
9bea5af41SShawn Guo  * This program is free software; you can redistribute it and/or
10bea5af41SShawn Guo  * modify it under the terms of the GNU General Public License
11bea5af41SShawn Guo  * as published by the Free Software Foundation; either version 2
12bea5af41SShawn Guo  * of the License, or (at your option) any later version.
13bea5af41SShawn Guo  * This program is distributed in the hope that it will be useful,
14bea5af41SShawn Guo  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15bea5af41SShawn Guo  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16bea5af41SShawn Guo  * GNU General Public License for more details.
17bea5af41SShawn Guo  *
18bea5af41SShawn Guo  * You should have received a copy of the GNU General Public License
19bea5af41SShawn Guo  * along with this program; if not, write to the Free Software
20bea5af41SShawn Guo  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21bea5af41SShawn Guo  * MA 02110-1301, USA.
22bea5af41SShawn Guo  */
23bea5af41SShawn Guo 
24bea5af41SShawn Guo #include <linux/interrupt.h>
25bea5af41SShawn Guo #include <linux/irq.h>
26bea5af41SShawn Guo #include <linux/clockchips.h>
27bea5af41SShawn Guo #include <linux/clk.h>
28bea5af41SShawn Guo #include <linux/delay.h>
29bea5af41SShawn Guo #include <linux/err.h>
30bea5af41SShawn Guo #include <linux/sched_clock.h>
31bea5af41SShawn Guo #include <linux/slab.h>
32bea5af41SShawn Guo #include <linux/of.h>
33bea5af41SShawn Guo #include <linux/of_address.h>
34bea5af41SShawn Guo #include <linux/of_irq.h>
35bea5af41SShawn Guo #include <soc/imx/timer.h>
36bea5af41SShawn Guo 
37bea5af41SShawn Guo /*
38bea5af41SShawn Guo  * There are 4 versions of the timer hardware on Freescale MXC hardware.
39bea5af41SShawn Guo  *  - MX1/MXL
40bea5af41SShawn Guo  *  - MX21, MX27.
41bea5af41SShawn Guo  *  - MX25, MX31, MX35, MX37, MX51, MX6Q(rev1.0)
42bea5af41SShawn Guo  *  - MX6DL, MX6SX, MX6Q(rev1.1+)
43bea5af41SShawn Guo  */
44bea5af41SShawn Guo 
45bea5af41SShawn Guo /* defines common for all i.MX */
46bea5af41SShawn Guo #define MXC_TCTL		0x00
47bea5af41SShawn Guo #define MXC_TCTL_TEN		(1 << 0) /* Enable module */
48bea5af41SShawn Guo #define MXC_TPRER		0x04
49bea5af41SShawn Guo 
50bea5af41SShawn Guo /* MX1, MX21, MX27 */
51bea5af41SShawn Guo #define MX1_2_TCTL_CLK_PCLK1	(1 << 1)
52bea5af41SShawn Guo #define MX1_2_TCTL_IRQEN	(1 << 4)
53bea5af41SShawn Guo #define MX1_2_TCTL_FRR		(1 << 8)
54bea5af41SShawn Guo #define MX1_2_TCMP		0x08
55bea5af41SShawn Guo #define MX1_2_TCN		0x10
56bea5af41SShawn Guo #define MX1_2_TSTAT		0x14
57bea5af41SShawn Guo 
58bea5af41SShawn Guo /* MX21, MX27 */
59bea5af41SShawn Guo #define MX2_TSTAT_CAPT		(1 << 1)
60bea5af41SShawn Guo #define MX2_TSTAT_COMP		(1 << 0)
61bea5af41SShawn Guo 
62bea5af41SShawn Guo /* MX31, MX35, MX25, MX5, MX6 */
63bea5af41SShawn Guo #define V2_TCTL_WAITEN		(1 << 3) /* Wait enable mode */
64bea5af41SShawn Guo #define V2_TCTL_CLK_IPG		(1 << 6)
65bea5af41SShawn Guo #define V2_TCTL_CLK_PER		(2 << 6)
66bea5af41SShawn Guo #define V2_TCTL_CLK_OSC_DIV8	(5 << 6)
67bea5af41SShawn Guo #define V2_TCTL_FRR		(1 << 9)
68bea5af41SShawn Guo #define V2_TCTL_24MEN		(1 << 10)
69bea5af41SShawn Guo #define V2_TPRER_PRE24M		12
70bea5af41SShawn Guo #define V2_IR			0x0c
71bea5af41SShawn Guo #define V2_TSTAT		0x08
72bea5af41SShawn Guo #define V2_TSTAT_OF1		(1 << 0)
73bea5af41SShawn Guo #define V2_TCN			0x24
74bea5af41SShawn Guo #define V2_TCMP			0x10
75bea5af41SShawn Guo 
76bea5af41SShawn Guo #define V2_TIMER_RATE_OSC_DIV8	3000000
77bea5af41SShawn Guo 
78bea5af41SShawn Guo struct imx_timer {
79bea5af41SShawn Guo 	enum imx_gpt_type type;
80bea5af41SShawn Guo 	void __iomem *base;
81bea5af41SShawn Guo 	int irq;
82bea5af41SShawn Guo 	struct clk *clk_per;
83bea5af41SShawn Guo 	struct clk *clk_ipg;
84bea5af41SShawn Guo 	const struct imx_gpt_data *gpt;
85bea5af41SShawn Guo 	struct clock_event_device ced;
86bea5af41SShawn Guo 	struct irqaction act;
87bea5af41SShawn Guo };
88bea5af41SShawn Guo 
89bea5af41SShawn Guo struct imx_gpt_data {
90bea5af41SShawn Guo 	int reg_tstat;
91bea5af41SShawn Guo 	int reg_tcn;
92bea5af41SShawn Guo 	int reg_tcmp;
93bea5af41SShawn Guo 	void (*gpt_setup_tctl)(struct imx_timer *imxtm);
94bea5af41SShawn Guo 	void (*gpt_irq_enable)(struct imx_timer *imxtm);
95bea5af41SShawn Guo 	void (*gpt_irq_disable)(struct imx_timer *imxtm);
96bea5af41SShawn Guo 	void (*gpt_irq_acknowledge)(struct imx_timer *imxtm);
97bea5af41SShawn Guo 	int (*set_next_event)(unsigned long evt,
98bea5af41SShawn Guo 			      struct clock_event_device *ced);
99bea5af41SShawn Guo };
100bea5af41SShawn Guo 
101bea5af41SShawn Guo static inline struct imx_timer *to_imx_timer(struct clock_event_device *ced)
102bea5af41SShawn Guo {
103bea5af41SShawn Guo 	return container_of(ced, struct imx_timer, ced);
104bea5af41SShawn Guo }
105bea5af41SShawn Guo 
106bea5af41SShawn Guo static void imx1_gpt_irq_disable(struct imx_timer *imxtm)
107bea5af41SShawn Guo {
108bea5af41SShawn Guo 	unsigned int tmp;
109bea5af41SShawn Guo 
110bea5af41SShawn Guo 	tmp = readl_relaxed(imxtm->base + MXC_TCTL);
111bea5af41SShawn Guo 	writel_relaxed(tmp & ~MX1_2_TCTL_IRQEN, imxtm->base + MXC_TCTL);
112bea5af41SShawn Guo }
113bea5af41SShawn Guo #define imx21_gpt_irq_disable imx1_gpt_irq_disable
114bea5af41SShawn Guo 
115bea5af41SShawn Guo static void imx31_gpt_irq_disable(struct imx_timer *imxtm)
116bea5af41SShawn Guo {
117bea5af41SShawn Guo 	writel_relaxed(0, imxtm->base + V2_IR);
118bea5af41SShawn Guo }
119bea5af41SShawn Guo #define imx6dl_gpt_irq_disable imx31_gpt_irq_disable
120bea5af41SShawn Guo 
121bea5af41SShawn Guo static void imx1_gpt_irq_enable(struct imx_timer *imxtm)
122bea5af41SShawn Guo {
123bea5af41SShawn Guo 	unsigned int tmp;
124bea5af41SShawn Guo 
125bea5af41SShawn Guo 	tmp = readl_relaxed(imxtm->base + MXC_TCTL);
126bea5af41SShawn Guo 	writel_relaxed(tmp | MX1_2_TCTL_IRQEN, imxtm->base + MXC_TCTL);
127bea5af41SShawn Guo }
128bea5af41SShawn Guo #define imx21_gpt_irq_enable imx1_gpt_irq_enable
129bea5af41SShawn Guo 
130bea5af41SShawn Guo static void imx31_gpt_irq_enable(struct imx_timer *imxtm)
131bea5af41SShawn Guo {
132bea5af41SShawn Guo 	writel_relaxed(1<<0, imxtm->base + V2_IR);
133bea5af41SShawn Guo }
134bea5af41SShawn Guo #define imx6dl_gpt_irq_enable imx31_gpt_irq_enable
135bea5af41SShawn Guo 
136bea5af41SShawn Guo static void imx1_gpt_irq_acknowledge(struct imx_timer *imxtm)
137bea5af41SShawn Guo {
138bea5af41SShawn Guo 	writel_relaxed(0, imxtm->base + MX1_2_TSTAT);
139bea5af41SShawn Guo }
140bea5af41SShawn Guo 
141bea5af41SShawn Guo static void imx21_gpt_irq_acknowledge(struct imx_timer *imxtm)
142bea5af41SShawn Guo {
143bea5af41SShawn Guo 	writel_relaxed(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
144bea5af41SShawn Guo 				imxtm->base + MX1_2_TSTAT);
145bea5af41SShawn Guo }
146bea5af41SShawn Guo 
147bea5af41SShawn Guo static void imx31_gpt_irq_acknowledge(struct imx_timer *imxtm)
148bea5af41SShawn Guo {
149bea5af41SShawn Guo 	writel_relaxed(V2_TSTAT_OF1, imxtm->base + V2_TSTAT);
150bea5af41SShawn Guo }
151bea5af41SShawn Guo #define imx6dl_gpt_irq_acknowledge imx31_gpt_irq_acknowledge
152bea5af41SShawn Guo 
153bea5af41SShawn Guo static void __iomem *sched_clock_reg;
154bea5af41SShawn Guo 
155bea5af41SShawn Guo static u64 notrace mxc_read_sched_clock(void)
156bea5af41SShawn Guo {
157bea5af41SShawn Guo 	return sched_clock_reg ? readl_relaxed(sched_clock_reg) : 0;
158bea5af41SShawn Guo }
159bea5af41SShawn Guo 
160bea5af41SShawn Guo static struct delay_timer imx_delay_timer;
161bea5af41SShawn Guo 
162bea5af41SShawn Guo static unsigned long imx_read_current_timer(void)
163bea5af41SShawn Guo {
164bea5af41SShawn Guo 	return readl_relaxed(sched_clock_reg);
165bea5af41SShawn Guo }
166bea5af41SShawn Guo 
167bea5af41SShawn Guo static int __init mxc_clocksource_init(struct imx_timer *imxtm)
168bea5af41SShawn Guo {
169bea5af41SShawn Guo 	unsigned int c = clk_get_rate(imxtm->clk_per);
170bea5af41SShawn Guo 	void __iomem *reg = imxtm->base + imxtm->gpt->reg_tcn;
171bea5af41SShawn Guo 
172bea5af41SShawn Guo 	imx_delay_timer.read_current_timer = &imx_read_current_timer;
173bea5af41SShawn Guo 	imx_delay_timer.freq = c;
174bea5af41SShawn Guo 	register_current_timer_delay(&imx_delay_timer);
175bea5af41SShawn Guo 
176bea5af41SShawn Guo 	sched_clock_reg = reg;
177bea5af41SShawn Guo 
178bea5af41SShawn Guo 	sched_clock_register(mxc_read_sched_clock, 32, c);
179bea5af41SShawn Guo 	return clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32,
180bea5af41SShawn Guo 			clocksource_mmio_readl_up);
181bea5af41SShawn Guo }
182bea5af41SShawn Guo 
183bea5af41SShawn Guo /* clock event */
184bea5af41SShawn Guo 
185bea5af41SShawn Guo static int mx1_2_set_next_event(unsigned long evt,
186bea5af41SShawn Guo 			      struct clock_event_device *ced)
187bea5af41SShawn Guo {
188bea5af41SShawn Guo 	struct imx_timer *imxtm = to_imx_timer(ced);
189bea5af41SShawn Guo 	unsigned long tcmp;
190bea5af41SShawn Guo 
191bea5af41SShawn Guo 	tcmp = readl_relaxed(imxtm->base + MX1_2_TCN) + evt;
192bea5af41SShawn Guo 
193bea5af41SShawn Guo 	writel_relaxed(tcmp, imxtm->base + MX1_2_TCMP);
194bea5af41SShawn Guo 
195bea5af41SShawn Guo 	return (int)(tcmp - readl_relaxed(imxtm->base + MX1_2_TCN)) < 0 ?
196bea5af41SShawn Guo 				-ETIME : 0;
197bea5af41SShawn Guo }
198bea5af41SShawn Guo 
199bea5af41SShawn Guo static int v2_set_next_event(unsigned long evt,
200bea5af41SShawn Guo 			      struct clock_event_device *ced)
201bea5af41SShawn Guo {
202bea5af41SShawn Guo 	struct imx_timer *imxtm = to_imx_timer(ced);
203bea5af41SShawn Guo 	unsigned long tcmp;
204bea5af41SShawn Guo 
205bea5af41SShawn Guo 	tcmp = readl_relaxed(imxtm->base + V2_TCN) + evt;
206bea5af41SShawn Guo 
207bea5af41SShawn Guo 	writel_relaxed(tcmp, imxtm->base + V2_TCMP);
208bea5af41SShawn Guo 
209bea5af41SShawn Guo 	return evt < 0x7fffffff &&
210bea5af41SShawn Guo 		(int)(tcmp - readl_relaxed(imxtm->base + V2_TCN)) < 0 ?
211bea5af41SShawn Guo 				-ETIME : 0;
212bea5af41SShawn Guo }
213bea5af41SShawn Guo 
21426b91f04SViresh Kumar static int mxc_shutdown(struct clock_event_device *ced)
21526b91f04SViresh Kumar {
21626b91f04SViresh Kumar 	struct imx_timer *imxtm = to_imx_timer(ced);
21726b91f04SViresh Kumar 	unsigned long flags;
21826b91f04SViresh Kumar 	u32 tcn;
21926b91f04SViresh Kumar 
22026b91f04SViresh Kumar 	/*
22126b91f04SViresh Kumar 	 * The timer interrupt generation is disabled at least
22226b91f04SViresh Kumar 	 * for enough time to call mxc_set_next_event()
22326b91f04SViresh Kumar 	 */
22426b91f04SViresh Kumar 	local_irq_save(flags);
22526b91f04SViresh Kumar 
22626b91f04SViresh Kumar 	/* Disable interrupt in GPT module */
22726b91f04SViresh Kumar 	imxtm->gpt->gpt_irq_disable(imxtm);
22826b91f04SViresh Kumar 
22926b91f04SViresh Kumar 	tcn = readl_relaxed(imxtm->base + imxtm->gpt->reg_tcn);
23026b91f04SViresh Kumar 	/* Set event time into far-far future */
23126b91f04SViresh Kumar 	writel_relaxed(tcn - 3, imxtm->base + imxtm->gpt->reg_tcmp);
23226b91f04SViresh Kumar 
23326b91f04SViresh Kumar 	/* Clear pending interrupt */
23426b91f04SViresh Kumar 	imxtm->gpt->gpt_irq_acknowledge(imxtm);
23526b91f04SViresh Kumar 
236bea5af41SShawn Guo #ifdef DEBUG
23726b91f04SViresh Kumar 	printk(KERN_INFO "%s: changing mode\n", __func__);
238bea5af41SShawn Guo #endif /* DEBUG */
239bea5af41SShawn Guo 
24026b91f04SViresh Kumar 	local_irq_restore(flags);
24126b91f04SViresh Kumar 
24226b91f04SViresh Kumar 	return 0;
24326b91f04SViresh Kumar }
24426b91f04SViresh Kumar 
24526b91f04SViresh Kumar static int mxc_set_oneshot(struct clock_event_device *ced)
246bea5af41SShawn Guo {
247bea5af41SShawn Guo 	struct imx_timer *imxtm = to_imx_timer(ced);
248bea5af41SShawn Guo 	unsigned long flags;
249bea5af41SShawn Guo 
250bea5af41SShawn Guo 	/*
251bea5af41SShawn Guo 	 * The timer interrupt generation is disabled at least
252bea5af41SShawn Guo 	 * for enough time to call mxc_set_next_event()
253bea5af41SShawn Guo 	 */
254bea5af41SShawn Guo 	local_irq_save(flags);
255bea5af41SShawn Guo 
256bea5af41SShawn Guo 	/* Disable interrupt in GPT module */
257bea5af41SShawn Guo 	imxtm->gpt->gpt_irq_disable(imxtm);
258bea5af41SShawn Guo 
25926b91f04SViresh Kumar 	if (!clockevent_state_oneshot(ced)) {
260bea5af41SShawn Guo 		u32 tcn = readl_relaxed(imxtm->base + imxtm->gpt->reg_tcn);
261bea5af41SShawn Guo 		/* Set event time into far-far future */
262bea5af41SShawn Guo 		writel_relaxed(tcn - 3, imxtm->base + imxtm->gpt->reg_tcmp);
263bea5af41SShawn Guo 
264bea5af41SShawn Guo 		/* Clear pending interrupt */
265bea5af41SShawn Guo 		imxtm->gpt->gpt_irq_acknowledge(imxtm);
266bea5af41SShawn Guo 	}
267bea5af41SShawn Guo 
268bea5af41SShawn Guo #ifdef DEBUG
26926b91f04SViresh Kumar 	printk(KERN_INFO "%s: changing mode\n", __func__);
270bea5af41SShawn Guo #endif /* DEBUG */
271bea5af41SShawn Guo 
272bea5af41SShawn Guo 	/*
273bea5af41SShawn Guo 	 * Do not put overhead of interrupt enable/disable into
274bea5af41SShawn Guo 	 * mxc_set_next_event(), the core has about 4 minutes
275bea5af41SShawn Guo 	 * to call mxc_set_next_event() or shutdown clock after
276bea5af41SShawn Guo 	 * mode switching
277bea5af41SShawn Guo 	 */
278bea5af41SShawn Guo 	imxtm->gpt->gpt_irq_enable(imxtm);
279bea5af41SShawn Guo 	local_irq_restore(flags);
28026b91f04SViresh Kumar 
28126b91f04SViresh Kumar 	return 0;
282bea5af41SShawn Guo }
283bea5af41SShawn Guo 
284bea5af41SShawn Guo /*
285bea5af41SShawn Guo  * IRQ handler for the timer
286bea5af41SShawn Guo  */
287bea5af41SShawn Guo static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
288bea5af41SShawn Guo {
289bea5af41SShawn Guo 	struct clock_event_device *ced = dev_id;
290bea5af41SShawn Guo 	struct imx_timer *imxtm = to_imx_timer(ced);
291bea5af41SShawn Guo 	uint32_t tstat;
292bea5af41SShawn Guo 
293bea5af41SShawn Guo 	tstat = readl_relaxed(imxtm->base + imxtm->gpt->reg_tstat);
294bea5af41SShawn Guo 
295bea5af41SShawn Guo 	imxtm->gpt->gpt_irq_acknowledge(imxtm);
296bea5af41SShawn Guo 
297bea5af41SShawn Guo 	ced->event_handler(ced);
298bea5af41SShawn Guo 
299bea5af41SShawn Guo 	return IRQ_HANDLED;
300bea5af41SShawn Guo }
301bea5af41SShawn Guo 
302bea5af41SShawn Guo static int __init mxc_clockevent_init(struct imx_timer *imxtm)
303bea5af41SShawn Guo {
304bea5af41SShawn Guo 	struct clock_event_device *ced = &imxtm->ced;
305bea5af41SShawn Guo 	struct irqaction *act = &imxtm->act;
306bea5af41SShawn Guo 
307bea5af41SShawn Guo 	ced->name = "mxc_timer1";
308f1c08c9bSLucas Stach 	ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
30926b91f04SViresh Kumar 	ced->set_state_shutdown = mxc_shutdown;
31026b91f04SViresh Kumar 	ced->set_state_oneshot = mxc_set_oneshot;
31126b91f04SViresh Kumar 	ced->tick_resume = mxc_shutdown;
312bea5af41SShawn Guo 	ced->set_next_event = imxtm->gpt->set_next_event;
313bea5af41SShawn Guo 	ced->rating = 200;
314bea5af41SShawn Guo 	ced->cpumask = cpumask_of(0);
315f1c08c9bSLucas Stach 	ced->irq = imxtm->irq;
316bea5af41SShawn Guo 	clockevents_config_and_register(ced, clk_get_rate(imxtm->clk_per),
317bea5af41SShawn Guo 					0xff, 0xfffffffe);
318bea5af41SShawn Guo 
319bea5af41SShawn Guo 	act->name = "i.MX Timer Tick";
320bea5af41SShawn Guo 	act->flags = IRQF_TIMER | IRQF_IRQPOLL;
321bea5af41SShawn Guo 	act->handler = mxc_timer_interrupt;
322bea5af41SShawn Guo 	act->dev_id = ced;
323bea5af41SShawn Guo 
324bea5af41SShawn Guo 	return setup_irq(imxtm->irq, act);
325bea5af41SShawn Guo }
326bea5af41SShawn Guo 
327bea5af41SShawn Guo static void imx1_gpt_setup_tctl(struct imx_timer *imxtm)
328bea5af41SShawn Guo {
329bea5af41SShawn Guo 	u32 tctl_val;
330bea5af41SShawn Guo 
331bea5af41SShawn Guo 	tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
332bea5af41SShawn Guo 	writel_relaxed(tctl_val, imxtm->base + MXC_TCTL);
333bea5af41SShawn Guo }
334bea5af41SShawn Guo #define imx21_gpt_setup_tctl imx1_gpt_setup_tctl
335bea5af41SShawn Guo 
336bea5af41SShawn Guo static void imx31_gpt_setup_tctl(struct imx_timer *imxtm)
337bea5af41SShawn Guo {
338bea5af41SShawn Guo 	u32 tctl_val;
339bea5af41SShawn Guo 
340bea5af41SShawn Guo 	tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
341bea5af41SShawn Guo 	if (clk_get_rate(imxtm->clk_per) == V2_TIMER_RATE_OSC_DIV8)
342bea5af41SShawn Guo 		tctl_val |= V2_TCTL_CLK_OSC_DIV8;
343bea5af41SShawn Guo 	else
344bea5af41SShawn Guo 		tctl_val |= V2_TCTL_CLK_PER;
345bea5af41SShawn Guo 
346bea5af41SShawn Guo 	writel_relaxed(tctl_val, imxtm->base + MXC_TCTL);
347bea5af41SShawn Guo }
348bea5af41SShawn Guo 
349bea5af41SShawn Guo static void imx6dl_gpt_setup_tctl(struct imx_timer *imxtm)
350bea5af41SShawn Guo {
351bea5af41SShawn Guo 	u32 tctl_val;
352bea5af41SShawn Guo 
353bea5af41SShawn Guo 	tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
354bea5af41SShawn Guo 	if (clk_get_rate(imxtm->clk_per) == V2_TIMER_RATE_OSC_DIV8) {
355bea5af41SShawn Guo 		tctl_val |= V2_TCTL_CLK_OSC_DIV8;
356bea5af41SShawn Guo 		/* 24 / 8 = 3 MHz */
357bea5af41SShawn Guo 		writel_relaxed(7 << V2_TPRER_PRE24M, imxtm->base + MXC_TPRER);
358bea5af41SShawn Guo 		tctl_val |= V2_TCTL_24MEN;
359bea5af41SShawn Guo 	} else {
360bea5af41SShawn Guo 		tctl_val |= V2_TCTL_CLK_PER;
361bea5af41SShawn Guo 	}
362bea5af41SShawn Guo 
363bea5af41SShawn Guo 	writel_relaxed(tctl_val, imxtm->base + MXC_TCTL);
364bea5af41SShawn Guo }
365bea5af41SShawn Guo 
366bea5af41SShawn Guo static const struct imx_gpt_data imx1_gpt_data = {
367bea5af41SShawn Guo 	.reg_tstat = MX1_2_TSTAT,
368bea5af41SShawn Guo 	.reg_tcn = MX1_2_TCN,
369bea5af41SShawn Guo 	.reg_tcmp = MX1_2_TCMP,
370bea5af41SShawn Guo 	.gpt_irq_enable = imx1_gpt_irq_enable,
371bea5af41SShawn Guo 	.gpt_irq_disable = imx1_gpt_irq_disable,
372bea5af41SShawn Guo 	.gpt_irq_acknowledge = imx1_gpt_irq_acknowledge,
373bea5af41SShawn Guo 	.gpt_setup_tctl = imx1_gpt_setup_tctl,
374bea5af41SShawn Guo 	.set_next_event = mx1_2_set_next_event,
375bea5af41SShawn Guo };
376bea5af41SShawn Guo 
377bea5af41SShawn Guo static const struct imx_gpt_data imx21_gpt_data = {
378bea5af41SShawn Guo 	.reg_tstat = MX1_2_TSTAT,
379bea5af41SShawn Guo 	.reg_tcn = MX1_2_TCN,
380bea5af41SShawn Guo 	.reg_tcmp = MX1_2_TCMP,
381bea5af41SShawn Guo 	.gpt_irq_enable = imx21_gpt_irq_enable,
382bea5af41SShawn Guo 	.gpt_irq_disable = imx21_gpt_irq_disable,
383bea5af41SShawn Guo 	.gpt_irq_acknowledge = imx21_gpt_irq_acknowledge,
384bea5af41SShawn Guo 	.gpt_setup_tctl = imx21_gpt_setup_tctl,
385bea5af41SShawn Guo 	.set_next_event = mx1_2_set_next_event,
386bea5af41SShawn Guo };
387bea5af41SShawn Guo 
388bea5af41SShawn Guo static const struct imx_gpt_data imx31_gpt_data = {
389bea5af41SShawn Guo 	.reg_tstat = V2_TSTAT,
390bea5af41SShawn Guo 	.reg_tcn = V2_TCN,
391bea5af41SShawn Guo 	.reg_tcmp = V2_TCMP,
392bea5af41SShawn Guo 	.gpt_irq_enable = imx31_gpt_irq_enable,
393bea5af41SShawn Guo 	.gpt_irq_disable = imx31_gpt_irq_disable,
394bea5af41SShawn Guo 	.gpt_irq_acknowledge = imx31_gpt_irq_acknowledge,
395bea5af41SShawn Guo 	.gpt_setup_tctl = imx31_gpt_setup_tctl,
396bea5af41SShawn Guo 	.set_next_event = v2_set_next_event,
397bea5af41SShawn Guo };
398bea5af41SShawn Guo 
399bea5af41SShawn Guo static const struct imx_gpt_data imx6dl_gpt_data = {
400bea5af41SShawn Guo 	.reg_tstat = V2_TSTAT,
401bea5af41SShawn Guo 	.reg_tcn = V2_TCN,
402bea5af41SShawn Guo 	.reg_tcmp = V2_TCMP,
403bea5af41SShawn Guo 	.gpt_irq_enable = imx6dl_gpt_irq_enable,
404bea5af41SShawn Guo 	.gpt_irq_disable = imx6dl_gpt_irq_disable,
405bea5af41SShawn Guo 	.gpt_irq_acknowledge = imx6dl_gpt_irq_acknowledge,
406bea5af41SShawn Guo 	.gpt_setup_tctl = imx6dl_gpt_setup_tctl,
407bea5af41SShawn Guo 	.set_next_event = v2_set_next_event,
408bea5af41SShawn Guo };
409bea5af41SShawn Guo 
410c11cd416SDaniel Lezcano static int __init _mxc_timer_init(struct imx_timer *imxtm)
411bea5af41SShawn Guo {
412c11cd416SDaniel Lezcano 	int ret;
413c11cd416SDaniel Lezcano 
414bea5af41SShawn Guo 	switch (imxtm->type) {
415bea5af41SShawn Guo 	case GPT_TYPE_IMX1:
416bea5af41SShawn Guo 		imxtm->gpt = &imx1_gpt_data;
417bea5af41SShawn Guo 		break;
418bea5af41SShawn Guo 	case GPT_TYPE_IMX21:
419bea5af41SShawn Guo 		imxtm->gpt = &imx21_gpt_data;
420bea5af41SShawn Guo 		break;
421bea5af41SShawn Guo 	case GPT_TYPE_IMX31:
422bea5af41SShawn Guo 		imxtm->gpt = &imx31_gpt_data;
423bea5af41SShawn Guo 		break;
424bea5af41SShawn Guo 	case GPT_TYPE_IMX6DL:
425bea5af41SShawn Guo 		imxtm->gpt = &imx6dl_gpt_data;
426bea5af41SShawn Guo 		break;
427bea5af41SShawn Guo 	default:
428c11cd416SDaniel Lezcano 		return -EINVAL;
429bea5af41SShawn Guo 	}
430bea5af41SShawn Guo 
431bea5af41SShawn Guo 	if (IS_ERR(imxtm->clk_per)) {
432bea5af41SShawn Guo 		pr_err("i.MX timer: unable to get clk\n");
433c11cd416SDaniel Lezcano 		return PTR_ERR(imxtm->clk_per);
434bea5af41SShawn Guo 	}
435bea5af41SShawn Guo 
436bea5af41SShawn Guo 	if (!IS_ERR(imxtm->clk_ipg))
437bea5af41SShawn Guo 		clk_prepare_enable(imxtm->clk_ipg);
438bea5af41SShawn Guo 
439bea5af41SShawn Guo 	clk_prepare_enable(imxtm->clk_per);
440bea5af41SShawn Guo 
441bea5af41SShawn Guo 	/*
442bea5af41SShawn Guo 	 * Initialise to a known state (all timers off, and timing reset)
443bea5af41SShawn Guo 	 */
444bea5af41SShawn Guo 
445bea5af41SShawn Guo 	writel_relaxed(0, imxtm->base + MXC_TCTL);
446bea5af41SShawn Guo 	writel_relaxed(0, imxtm->base + MXC_TPRER); /* see datasheet note */
447bea5af41SShawn Guo 
448bea5af41SShawn Guo 	imxtm->gpt->gpt_setup_tctl(imxtm);
449bea5af41SShawn Guo 
450bea5af41SShawn Guo 	/* init and register the timer to the framework */
451c11cd416SDaniel Lezcano 	ret = mxc_clocksource_init(imxtm);
452c11cd416SDaniel Lezcano 	if (ret)
453c11cd416SDaniel Lezcano 		return ret;
454c11cd416SDaniel Lezcano 
455c11cd416SDaniel Lezcano 	return mxc_clockevent_init(imxtm);
456bea5af41SShawn Guo }
457bea5af41SShawn Guo 
458bea5af41SShawn Guo void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type)
459bea5af41SShawn Guo {
460bea5af41SShawn Guo 	struct imx_timer *imxtm;
461bea5af41SShawn Guo 
462bea5af41SShawn Guo 	imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL);
463bea5af41SShawn Guo 	BUG_ON(!imxtm);
464bea5af41SShawn Guo 
465bea5af41SShawn Guo 	imxtm->clk_per = clk_get_sys("imx-gpt.0", "per");
466bea5af41SShawn Guo 	imxtm->clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
467bea5af41SShawn Guo 
468bea5af41SShawn Guo 	imxtm->base = ioremap(pbase, SZ_4K);
469bea5af41SShawn Guo 	BUG_ON(!imxtm->base);
470bea5af41SShawn Guo 
471bea5af41SShawn Guo 	imxtm->type = type;
472be3b0f9bSGuenter Roeck 	imxtm->irq = irq;
473bea5af41SShawn Guo 
474bea5af41SShawn Guo 	_mxc_timer_init(imxtm);
475bea5af41SShawn Guo }
476bea5af41SShawn Guo 
477c11cd416SDaniel Lezcano static int __init mxc_timer_init_dt(struct device_node *np,  enum imx_gpt_type type)
478bea5af41SShawn Guo {
479bea5af41SShawn Guo 	struct imx_timer *imxtm;
480bea5af41SShawn Guo 	static int initialized;
481c11cd416SDaniel Lezcano 	int ret;
482bea5af41SShawn Guo 
483bea5af41SShawn Guo 	/* Support one instance only */
484bea5af41SShawn Guo 	if (initialized)
485c11cd416SDaniel Lezcano 		return 0;
486bea5af41SShawn Guo 
487bea5af41SShawn Guo 	imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL);
488c11cd416SDaniel Lezcano 	if (!imxtm)
489c11cd416SDaniel Lezcano 		return -ENOMEM;
490bea5af41SShawn Guo 
491bea5af41SShawn Guo 	imxtm->base = of_iomap(np, 0);
492c11cd416SDaniel Lezcano 	if (!imxtm->base)
493c11cd416SDaniel Lezcano 		return -ENXIO;
494c11cd416SDaniel Lezcano 
495bea5af41SShawn Guo 	imxtm->irq = irq_of_parse_and_map(np, 0);
496c11cd416SDaniel Lezcano 	if (imxtm->irq <= 0)
497c11cd416SDaniel Lezcano 		return -EINVAL;
498bea5af41SShawn Guo 
499bea5af41SShawn Guo 	imxtm->clk_ipg = of_clk_get_by_name(np, "ipg");
500bea5af41SShawn Guo 
501bea5af41SShawn Guo 	/* Try osc_per first, and fall back to per otherwise */
502bea5af41SShawn Guo 	imxtm->clk_per = of_clk_get_by_name(np, "osc_per");
503bea5af41SShawn Guo 	if (IS_ERR(imxtm->clk_per))
504bea5af41SShawn Guo 		imxtm->clk_per = of_clk_get_by_name(np, "per");
505bea5af41SShawn Guo 
506bea5af41SShawn Guo 	imxtm->type = type;
507bea5af41SShawn Guo 
508c11cd416SDaniel Lezcano 	ret = _mxc_timer_init(imxtm);
509c11cd416SDaniel Lezcano 	if (ret)
510c11cd416SDaniel Lezcano 		return ret;
511bea5af41SShawn Guo 
512bea5af41SShawn Guo 	initialized = 1;
513c11cd416SDaniel Lezcano 
514c11cd416SDaniel Lezcano 	return 0;
515bea5af41SShawn Guo }
516bea5af41SShawn Guo 
517c11cd416SDaniel Lezcano static int __init imx1_timer_init_dt(struct device_node *np)
518bea5af41SShawn Guo {
519c11cd416SDaniel Lezcano 	return mxc_timer_init_dt(np, GPT_TYPE_IMX1);
520bea5af41SShawn Guo }
521bea5af41SShawn Guo 
522c11cd416SDaniel Lezcano static int __init imx21_timer_init_dt(struct device_node *np)
523bea5af41SShawn Guo {
524c11cd416SDaniel Lezcano 	return mxc_timer_init_dt(np, GPT_TYPE_IMX21);
525bea5af41SShawn Guo }
526bea5af41SShawn Guo 
527c11cd416SDaniel Lezcano static int __init imx31_timer_init_dt(struct device_node *np)
528bea5af41SShawn Guo {
529bea5af41SShawn Guo 	enum imx_gpt_type type = GPT_TYPE_IMX31;
530bea5af41SShawn Guo 
531bea5af41SShawn Guo 	/*
532bea5af41SShawn Guo 	 * We were using the same compatible string for i.MX6Q/D and i.MX6DL/S
533bea5af41SShawn Guo 	 * GPT device, while they actually have different programming model.
534bea5af41SShawn Guo 	 * This is a workaround to keep the existing i.MX6DL/S DTBs continue
535bea5af41SShawn Guo 	 * working with the new kernel.
536bea5af41SShawn Guo 	 */
537bea5af41SShawn Guo 	if (of_machine_is_compatible("fsl,imx6dl"))
538bea5af41SShawn Guo 		type = GPT_TYPE_IMX6DL;
539bea5af41SShawn Guo 
540c11cd416SDaniel Lezcano 	return mxc_timer_init_dt(np, type);
541bea5af41SShawn Guo }
542bea5af41SShawn Guo 
543c11cd416SDaniel Lezcano static int __init imx6dl_timer_init_dt(struct device_node *np)
544bea5af41SShawn Guo {
545c11cd416SDaniel Lezcano 	return mxc_timer_init_dt(np, GPT_TYPE_IMX6DL);
546bea5af41SShawn Guo }
547bea5af41SShawn Guo 
548*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt);
549*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt);
550*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt);
551*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt);
552*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt);
553*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt);
554*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt);
555*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt);
556*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt);
557*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt);
558*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt);
559*17273395SDaniel Lezcano TIMER_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt);
560