blob: 571c14b3649715342bdcfcc2bdb153368ea06d59 [file] [log] [blame]
Tony Lindgren92105bb2005-09-07 17:20:26 +01001/*
2 * linux/arch/arm/plat-omap/dmtimer.c
3 *
4 * OMAP Dual-Mode Timers
5 *
Tarun Kanti DebBarma97933d62011-09-20 17:00:17 +05306 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
7 * Tarun Kanti DebBarma <tarun.kanti@ti.com>
8 * Thara Gopinath <thara@ti.com>
9 *
10 * dmtimer adaptation to platform_driver.
11 *
Tony Lindgren92105bb2005-09-07 17:20:26 +010012 * Copyright (C) 2005 Nokia Corporation
Timo Teras77900a22006-06-26 16:16:12 -070013 * OMAP2 support by Juha Yrjola
14 * API improvements and OMAP2 clock framework support by Timo Teras
Tony Lindgren92105bb2005-09-07 17:20:26 +010015 *
Santosh Shilimkar44169072009-05-28 14:16:04 -070016 * Copyright (C) 2009 Texas Instruments
17 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
18 *
Tony Lindgren92105bb2005-09-07 17:20:26 +010019 * This program is free software; you can redistribute it and/or modify it
20 * under the terms of the GNU General Public License as published by the
21 * Free Software Foundation; either version 2 of the License, or (at your
22 * option) any later version.
23 *
24 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
27 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * You should have received a copy of the GNU General Public License along
34 * with this program; if not, write to the Free Software Foundation, Inc.,
35 * 675 Mass Ave, Cambridge, MA 02139, USA.
36 */
37
38#include <linux/init.h>
Timo Teras77900a22006-06-26 16:16:12 -070039#include <linux/spinlock.h>
40#include <linux/errno.h>
41#include <linux/list.h>
42#include <linux/clk.h>
43#include <linux/delay.h>
Russell Kingfced80c2008-09-06 12:10:45 +010044#include <linux/io.h>
Timo Kokkonen6c366e32009-03-23 18:07:46 -070045#include <linux/module.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010046#include <mach/hardware.h>
Tony Lindgrence491cf2009-10-20 09:40:47 -070047#include <plat/dmtimer.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010048#include <mach/irqs.h>
Tony Lindgren92105bb2005-09-07 17:20:26 +010049
Tony Lindgren882c0512010-02-12 12:26:46 -080050static int dm_timer_count;
51
Tony Lindgren882c0512010-02-12 12:26:46 -080052#ifdef CONFIG_ARCH_OMAP2
Syed Mohammed, Khasim471b3aa2007-06-21 21:48:07 -070053static struct omap_dm_timer omap2_dm_timers[] = {
Timo Teras77900a22006-06-26 16:16:12 -070054 { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
55 { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
56 { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
57 { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
58 { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
59 { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
60 { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
61 { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
62 { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
63 { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
64 { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
65 { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
66};
67
Syed Mohammed, Khasim471b3aa2007-06-21 21:48:07 -070068static const char *omap2_dm_source_names[] __initdata = {
Timo Teras83379c82006-06-26 16:16:23 -070069 "sys_ck",
70 "func_32k_ck",
Syed Mohammed, Khasim471b3aa2007-06-21 21:48:07 -070071 "alt_ck",
72 NULL
Timo Teras83379c82006-06-26 16:16:23 -070073};
74
Santosh Shilimkaraea2a5b2009-05-25 11:08:36 -070075static struct clk *omap2_dm_source_clocks[3];
Tony Lindgren882c0512010-02-12 12:26:46 -080076static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
Timo Teras83379c82006-06-26 16:16:23 -070077
Tony Lindgren882c0512010-02-12 12:26:46 -080078#else
Syed Mohammed, Khasimce2df9c2007-06-25 22:55:39 -070079#define omap2_dm_timers NULL
Tony Lindgren882c0512010-02-12 12:26:46 -080080#define omap2_dm_timer_count 0
Syed Mohammed, Khasimce2df9c2007-06-25 22:55:39 -070081#define omap2_dm_source_names NULL
82#define omap2_dm_source_clocks NULL
Tony Lindgren882c0512010-02-12 12:26:46 -080083#endif /* CONFIG_ARCH_OMAP2 */
Syed Mohammed, Khasimce2df9c2007-06-25 22:55:39 -070084
Tony Lindgren882c0512010-02-12 12:26:46 -080085#ifdef CONFIG_ARCH_OMAP3
Syed Mohammed, Khasimce2df9c2007-06-25 22:55:39 -070086static struct omap_dm_timer omap3_dm_timers[] = {
87 { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
88 { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
89 { .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
90 { .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
91 { .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
92 { .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
93 { .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
94 { .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
95 { .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
96 { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
97 { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
Paul Walmsley9198a402009-04-23 21:11:08 -060098 { .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
Syed Mohammed, Khasimce2df9c2007-06-25 22:55:39 -070099};
100
101static const char *omap3_dm_source_names[] __initdata = {
102 "sys_ck",
103 "omap_32k_fck",
104 NULL
105};
106
Santosh Shilimkaraea2a5b2009-05-25 11:08:36 -0700107static struct clk *omap3_dm_source_clocks[2];
Tony Lindgren882c0512010-02-12 12:26:46 -0800108static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
Syed Mohammed, Khasimce2df9c2007-06-25 22:55:39 -0700109
Tony Lindgren882c0512010-02-12 12:26:46 -0800110#else
Santosh Shilimkar44169072009-05-28 14:16:04 -0700111#define omap3_dm_timers NULL
Tony Lindgren882c0512010-02-12 12:26:46 -0800112#define omap3_dm_timer_count 0
Santosh Shilimkar44169072009-05-28 14:16:04 -0700113#define omap3_dm_source_names NULL
114#define omap3_dm_source_clocks NULL
Tony Lindgren882c0512010-02-12 12:26:46 -0800115#endif /* CONFIG_ARCH_OMAP3 */
Santosh Shilimkar44169072009-05-28 14:16:04 -0700116
Tony Lindgren882c0512010-02-12 12:26:46 -0800117#ifdef CONFIG_ARCH_OMAP4
Santosh Shilimkar44169072009-05-28 14:16:04 -0700118static struct omap_dm_timer omap4_dm_timers[] = {
Santosh Shilimkar5772ca72010-02-18 03:14:12 +0530119 { .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
120 { .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
121 { .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
122 { .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
123 { .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
124 { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 },
125 { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
126 { .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
127 { .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
128 { .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
129 { .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
130 { .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
Santosh Shilimkar44169072009-05-28 14:16:04 -0700131};
132static const char *omap4_dm_source_names[] __initdata = {
Rajendra Nayak1dc993b2010-05-18 20:24:00 -0600133 "sys_clkin_ck",
134 "sys_32k_ck",
Santosh Shilimkar44169072009-05-28 14:16:04 -0700135 NULL
136};
137static struct clk *omap4_dm_source_clocks[2];
Tony Lindgren882c0512010-02-12 12:26:46 -0800138static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
Santosh Shilimkar44169072009-05-28 14:16:04 -0700139
Timo Teras77900a22006-06-26 16:16:12 -0700140#else
Tony Lindgren882c0512010-02-12 12:26:46 -0800141#define omap4_dm_timers NULL
142#define omap4_dm_timer_count 0
143#define omap4_dm_source_names NULL
144#define omap4_dm_source_clocks NULL
145#endif /* CONFIG_ARCH_OMAP4 */
Timo Teras77900a22006-06-26 16:16:12 -0700146
Syed Mohammed, Khasim471b3aa2007-06-21 21:48:07 -0700147static struct omap_dm_timer *dm_timers;
Santosh Shilimkaraea2a5b2009-05-25 11:08:36 -0700148static const char **dm_source_names;
Syed Mohammed, Khasim471b3aa2007-06-21 21:48:07 -0700149static struct clk **dm_source_clocks;
150
Tony Lindgren92105bb2005-09-07 17:20:26 +0100151static spinlock_t dm_timer_lock;
152
Richard Woodruff0f0d0802008-07-03 12:24:30 +0300153/*
154 * Reads timer registers in posted and non-posted mode. The posted mode bit
155 * is encoded in reg. Note that in posted mode write pending bit must be
156 * checked. Otherwise a read of a non completed write will produce an error.
157 */
158static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100159{
Tony Lindgrenee17f112011-09-16 15:44:20 -0700160 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
161 return __omap_dm_timer_read(timer, reg, timer->posted);
Timo Teras77900a22006-06-26 16:16:12 -0700162}
163
Richard Woodruff0f0d0802008-07-03 12:24:30 +0300164/*
165 * Writes timer registers in posted and non-posted mode. The posted mode bit
166 * is encoded in reg. Note that in posted mode the write pending bit must be
167 * checked. Otherwise a write on a register which has a pending write will be
168 * lost.
169 */
170static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
171 u32 value)
Timo Teras77900a22006-06-26 16:16:12 -0700172{
Tony Lindgrenee17f112011-09-16 15:44:20 -0700173 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
174 __omap_dm_timer_write(timer, reg, value, timer->posted);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100175}
176
Timo Teras77900a22006-06-26 16:16:12 -0700177static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100178{
Timo Teras77900a22006-06-26 16:16:12 -0700179 int c;
180
Tony Lindgrenee17f112011-09-16 15:44:20 -0700181 if (!timer->sys_stat)
182 return;
183
Timo Teras77900a22006-06-26 16:16:12 -0700184 c = 0;
Tony Lindgrenee17f112011-09-16 15:44:20 -0700185 while (!(__raw_readl(timer->sys_stat) & 1)) {
Timo Teras77900a22006-06-26 16:16:12 -0700186 c++;
187 if (c > 100000) {
188 printk(KERN_ERR "Timer failed to reset\n");
189 return;
190 }
191 }
Tony Lindgren92105bb2005-09-07 17:20:26 +0100192}
193
Timo Teras77900a22006-06-26 16:16:12 -0700194static void omap_dm_timer_reset(struct omap_dm_timer *timer)
195{
Tony Lindgrencaf64f22011-03-29 15:54:48 -0700196 int autoidle = 0, wakeup = 0;
Timo Teras77900a22006-06-26 16:16:12 -0700197
Juha Yrjola39020842006-09-25 12:41:44 +0300198 if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
Timo Terase32f7ec2006-06-26 16:16:13 -0700199 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
200 omap_dm_timer_wait_for_reset(timer);
201 }
Timo Teras12583a72006-09-25 12:41:42 +0300202 omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
Timo Teras77900a22006-06-26 16:16:12 -0700203
Ambresh Kba503482011-06-15 21:12:35 +0000204 /* Enable autoidle on OMAP2+ */
205 if (cpu_class_is_omap2())
Tony Lindgrencaf64f22011-03-29 15:54:48 -0700206 autoidle = 1;
Tero Kristo4ce1e5e2011-03-10 03:50:54 -0700207
Richard Woodruff0f0d0802008-07-03 12:24:30 +0300208 /*
Kevin Hilman219c5b92009-04-23 21:11:08 -0600209 * Enable wake-up on OMAP2 CPUs.
Richard Woodruff0f0d0802008-07-03 12:24:30 +0300210 */
Kevin Hilman219c5b92009-04-23 21:11:08 -0600211 if (cpu_class_is_omap2())
Tony Lindgrencaf64f22011-03-29 15:54:48 -0700212 wakeup = 1;
Richard Woodruff0f0d0802008-07-03 12:24:30 +0300213
Tony Lindgrenee17f112011-09-16 15:44:20 -0700214 __omap_dm_timer_reset(timer, autoidle, wakeup);
Richard Woodruff0f0d0802008-07-03 12:24:30 +0300215 timer->posted = 1;
Timo Teras77900a22006-06-26 16:16:12 -0700216}
217
Tony Lindgrencaf64f22011-03-29 15:54:48 -0700218void omap_dm_timer_prepare(struct omap_dm_timer *timer)
Timo Teras77900a22006-06-26 16:16:12 -0700219{
Timo Teras12583a72006-09-25 12:41:42 +0300220 omap_dm_timer_enable(timer);
Timo Teras77900a22006-06-26 16:16:12 -0700221 omap_dm_timer_reset(timer);
222}
223
224struct omap_dm_timer *omap_dm_timer_request(void)
225{
226 struct omap_dm_timer *timer = NULL;
227 unsigned long flags;
228 int i;
229
230 spin_lock_irqsave(&dm_timer_lock, flags);
231 for (i = 0; i < dm_timer_count; i++) {
232 if (dm_timers[i].reserved)
233 continue;
234
235 timer = &dm_timers[i];
Timo Teras83379c82006-06-26 16:16:23 -0700236 timer->reserved = 1;
Timo Teras77900a22006-06-26 16:16:12 -0700237 break;
238 }
239 spin_unlock_irqrestore(&dm_timer_lock, flags);
240
Timo Teras83379c82006-06-26 16:16:23 -0700241 if (timer != NULL)
242 omap_dm_timer_prepare(timer);
243
Timo Teras77900a22006-06-26 16:16:12 -0700244 return timer;
245}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700246EXPORT_SYMBOL_GPL(omap_dm_timer_request);
Timo Teras77900a22006-06-26 16:16:12 -0700247
248struct omap_dm_timer *omap_dm_timer_request_specific(int id)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100249{
250 struct omap_dm_timer *timer;
Timo Teras77900a22006-06-26 16:16:12 -0700251 unsigned long flags;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100252
Timo Teras77900a22006-06-26 16:16:12 -0700253 spin_lock_irqsave(&dm_timer_lock, flags);
254 if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
255 spin_unlock_irqrestore(&dm_timer_lock, flags);
256 printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
Harvey Harrison8e86f422008-03-04 15:08:02 -0800257 __FILE__, __LINE__, __func__, id);
Timo Teras77900a22006-06-26 16:16:12 -0700258 dump_stack();
259 return NULL;
260 }
Tony Lindgren92105bb2005-09-07 17:20:26 +0100261
Timo Teras77900a22006-06-26 16:16:12 -0700262 timer = &dm_timers[id-1];
Timo Teras83379c82006-06-26 16:16:23 -0700263 timer->reserved = 1;
Timo Teras77900a22006-06-26 16:16:12 -0700264 spin_unlock_irqrestore(&dm_timer_lock, flags);
265
Timo Teras83379c82006-06-26 16:16:23 -0700266 omap_dm_timer_prepare(timer);
267
Timo Teras77900a22006-06-26 16:16:12 -0700268 return timer;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100269}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700270EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100271
Timo Teras77900a22006-06-26 16:16:12 -0700272void omap_dm_timer_free(struct omap_dm_timer *timer)
273{
Timo Teras12583a72006-09-25 12:41:42 +0300274 omap_dm_timer_enable(timer);
Timo Teras77900a22006-06-26 16:16:12 -0700275 omap_dm_timer_reset(timer);
Timo Teras12583a72006-09-25 12:41:42 +0300276 omap_dm_timer_disable(timer);
Timo Terasfa4bb622006-09-25 12:41:35 +0300277
Timo Teras77900a22006-06-26 16:16:12 -0700278 WARN_ON(!timer->reserved);
279 timer->reserved = 0;
280}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700281EXPORT_SYMBOL_GPL(omap_dm_timer_free);
Timo Teras77900a22006-06-26 16:16:12 -0700282
Timo Teras12583a72006-09-25 12:41:42 +0300283void omap_dm_timer_enable(struct omap_dm_timer *timer)
284{
285 if (timer->enabled)
286 return;
287
Tony Lindgren882c0512010-02-12 12:26:46 -0800288#ifdef CONFIG_ARCH_OMAP2PLUS
289 if (cpu_class_is_omap2()) {
290 clk_enable(timer->fclk);
291 clk_enable(timer->iclk);
292 }
293#endif
Timo Teras12583a72006-09-25 12:41:42 +0300294
295 timer->enabled = 1;
296}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700297EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
Timo Teras12583a72006-09-25 12:41:42 +0300298
299void omap_dm_timer_disable(struct omap_dm_timer *timer)
300{
301 if (!timer->enabled)
302 return;
303
Tony Lindgren882c0512010-02-12 12:26:46 -0800304#ifdef CONFIG_ARCH_OMAP2PLUS
305 if (cpu_class_is_omap2()) {
306 clk_disable(timer->iclk);
307 clk_disable(timer->fclk);
308 }
309#endif
Timo Teras12583a72006-09-25 12:41:42 +0300310
311 timer->enabled = 0;
312}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700313EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
Timo Teras12583a72006-09-25 12:41:42 +0300314
Timo Teras77900a22006-06-26 16:16:12 -0700315int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
316{
317 return timer->irq;
318}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700319EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
Timo Teras77900a22006-06-26 16:16:12 -0700320
321#if defined(CONFIG_ARCH_OMAP1)
322
Tony Lindgrena569c6e2006-04-02 17:46:21 +0100323/**
324 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
325 * @inputmask: current value of idlect mask
326 */
327__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
328{
Timo Teras77900a22006-06-26 16:16:12 -0700329 int i;
Tony Lindgrena569c6e2006-04-02 17:46:21 +0100330
331 /* If ARMXOR cannot be idled this function call is unnecessary */
332 if (!(inputmask & (1 << 1)))
333 return inputmask;
334
335 /* If any active timer is using ARMXOR return modified mask */
Timo Teras77900a22006-06-26 16:16:12 -0700336 for (i = 0; i < dm_timer_count; i++) {
337 u32 l;
338
Tony Lindgren35912c72006-07-01 19:56:42 +0100339 l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
Timo Teras77900a22006-06-26 16:16:12 -0700340 if (l & OMAP_TIMER_CTRL_ST) {
341 if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
Tony Lindgrena569c6e2006-04-02 17:46:21 +0100342 inputmask &= ~(1 << 1);
343 else
344 inputmask &= ~(1 << 2);
345 }
Timo Teras77900a22006-06-26 16:16:12 -0700346 }
Tony Lindgrena569c6e2006-04-02 17:46:21 +0100347
348 return inputmask;
349}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700350EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
Tony Lindgrena569c6e2006-04-02 17:46:21 +0100351
Tony Lindgren140455f2010-02-12 12:26:48 -0800352#else
Timo Teras77900a22006-06-26 16:16:12 -0700353
354struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
355{
Timo Terasfa4bb622006-09-25 12:41:35 +0300356 return timer->fclk;
Timo Teras77900a22006-06-26 16:16:12 -0700357}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700358EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
Timo Teras77900a22006-06-26 16:16:12 -0700359
360__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
361{
362 BUG();
Dirk Behme21218802006-12-06 17:14:00 -0800363
364 return 0;
Timo Teras77900a22006-06-26 16:16:12 -0700365}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700366EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
Timo Teras77900a22006-06-26 16:16:12 -0700367
368#endif
369
370void omap_dm_timer_trigger(struct omap_dm_timer *timer)
371{
372 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
373}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700374EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
Timo Teras77900a22006-06-26 16:16:12 -0700375
376void omap_dm_timer_start(struct omap_dm_timer *timer)
377{
378 u32 l;
379
380 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
381 if (!(l & OMAP_TIMER_CTRL_ST)) {
382 l |= OMAP_TIMER_CTRL_ST;
383 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
384 }
385}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700386EXPORT_SYMBOL_GPL(omap_dm_timer_start);
Timo Teras77900a22006-06-26 16:16:12 -0700387
388void omap_dm_timer_stop(struct omap_dm_timer *timer)
389{
Tony Lindgrencaf64f22011-03-29 15:54:48 -0700390 unsigned long rate = 0;
Timo Teras77900a22006-06-26 16:16:12 -0700391
Tony Lindgren140455f2010-02-12 12:26:48 -0800392#ifdef CONFIG_ARCH_OMAP2PLUS
Tony Lindgrencaf64f22011-03-29 15:54:48 -0700393 rate = clk_get_rate(timer->fclk);
Tero Kristo5c3db362009-10-23 19:03:47 +0300394#endif
Tony Lindgrencaf64f22011-03-29 15:54:48 -0700395
Tony Lindgrenee17f112011-09-16 15:44:20 -0700396 __omap_dm_timer_stop(timer, timer->posted, rate);
Timo Teras77900a22006-06-26 16:16:12 -0700397}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700398EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
Timo Teras77900a22006-06-26 16:16:12 -0700399
Paul Walmsleyf2480762009-04-23 21:11:10 -0600400int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100401{
Timo Teras77900a22006-06-26 16:16:12 -0700402 if (source < 0 || source >= 3)
Paul Walmsleyf2480762009-04-23 21:11:10 -0600403 return -EINVAL;
Timo Teras77900a22006-06-26 16:16:12 -0700404
Tarun Kanti DebBarma97933d62011-09-20 17:00:17 +0530405#ifdef CONFIG_ARCH_OMAP2PLUS
Tony Lindgrencaf64f22011-03-29 15:54:48 -0700406 return __omap_dm_timer_set_source(timer->fclk,
407 dm_source_clocks[source]);
Tarun Kanti DebBarma97933d62011-09-20 17:00:17 +0530408#else
409 return 0;
410#endif
Timo Teras77900a22006-06-26 16:16:12 -0700411}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700412EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
Timo Teras77900a22006-06-26 16:16:12 -0700413
Timo Teras77900a22006-06-26 16:16:12 -0700414void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
415 unsigned int load)
416{
417 u32 l;
418
419 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
420 if (autoreload)
421 l |= OMAP_TIMER_CTRL_AR;
422 else
423 l &= ~OMAP_TIMER_CTRL_AR;
424 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
425 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
Richard Woodruff0f0d0802008-07-03 12:24:30 +0300426
Timo Teras77900a22006-06-26 16:16:12 -0700427 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
428}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700429EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
Timo Teras77900a22006-06-26 16:16:12 -0700430
Richard Woodruff3fddd092008-07-03 12:24:30 +0300431/* Optimized set_load which removes costly spin wait in timer_start */
432void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
433 unsigned int load)
434{
435 u32 l;
436
437 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
Paul Walmsley64ce2902008-12-10 17:36:34 -0800438 if (autoreload) {
Richard Woodruff3fddd092008-07-03 12:24:30 +0300439 l |= OMAP_TIMER_CTRL_AR;
Paul Walmsley64ce2902008-12-10 17:36:34 -0800440 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
441 } else {
Richard Woodruff3fddd092008-07-03 12:24:30 +0300442 l &= ~OMAP_TIMER_CTRL_AR;
Paul Walmsley64ce2902008-12-10 17:36:34 -0800443 }
Richard Woodruff3fddd092008-07-03 12:24:30 +0300444 l |= OMAP_TIMER_CTRL_ST;
445
Tony Lindgrenee17f112011-09-16 15:44:20 -0700446 __omap_dm_timer_load_start(timer, l, load, timer->posted);
Richard Woodruff3fddd092008-07-03 12:24:30 +0300447}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700448EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
Richard Woodruff3fddd092008-07-03 12:24:30 +0300449
Timo Teras77900a22006-06-26 16:16:12 -0700450void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
451 unsigned int match)
452{
453 u32 l;
454
455 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
Timo Teras83379c82006-06-26 16:16:23 -0700456 if (enable)
Timo Teras77900a22006-06-26 16:16:12 -0700457 l |= OMAP_TIMER_CTRL_CE;
458 else
459 l &= ~OMAP_TIMER_CTRL_CE;
460 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
461 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100462}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700463EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100464
Timo Teras77900a22006-06-26 16:16:12 -0700465void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
466 int toggle, int trigger)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100467{
Timo Teras77900a22006-06-26 16:16:12 -0700468 u32 l;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100469
Timo Teras77900a22006-06-26 16:16:12 -0700470 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
471 l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
472 OMAP_TIMER_CTRL_PT | (0x03 << 10));
473 if (def_on)
474 l |= OMAP_TIMER_CTRL_SCPWM;
475 if (toggle)
476 l |= OMAP_TIMER_CTRL_PT;
477 l |= trigger << 10;
478 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
479}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700480EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
Timo Teras77900a22006-06-26 16:16:12 -0700481
482void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
483{
484 u32 l;
485
486 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
487 l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
488 if (prescaler >= 0x00 && prescaler <= 0x07) {
489 l |= OMAP_TIMER_CTRL_PRE;
490 l |= prescaler << 2;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100491 }
Timo Teras77900a22006-06-26 16:16:12 -0700492 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100493}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700494EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100495
496void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
Timo Teras77900a22006-06-26 16:16:12 -0700497 unsigned int value)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100498{
Tony Lindgrenee17f112011-09-16 15:44:20 -0700499 __omap_dm_timer_int_enable(timer, value);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100500}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700501EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100502
503unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
504{
Timo Terasfa4bb622006-09-25 12:41:35 +0300505 unsigned int l;
506
Tony Lindgrenee17f112011-09-16 15:44:20 -0700507 l = __raw_readl(timer->irq_stat);
Timo Terasfa4bb622006-09-25 12:41:35 +0300508
509 return l;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100510}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700511EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100512
513void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
514{
Tony Lindgrenee17f112011-09-16 15:44:20 -0700515 __omap_dm_timer_write_status(timer, value);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100516}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700517EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100518
Tony Lindgren92105bb2005-09-07 17:20:26 +0100519unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
520{
Tony Lindgrenee17f112011-09-16 15:44:20 -0700521 return __omap_dm_timer_read_counter(timer, timer->posted);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100522}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700523EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100524
Timo Teras83379c82006-06-26 16:16:23 -0700525void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
526{
Timo Terasfa4bb622006-09-25 12:41:35 +0300527 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
Timo Teras83379c82006-06-26 16:16:23 -0700528}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700529EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
Timo Teras83379c82006-06-26 16:16:23 -0700530
Timo Teras77900a22006-06-26 16:16:12 -0700531int omap_dm_timers_active(void)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100532{
Timo Teras77900a22006-06-26 16:16:12 -0700533 int i;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100534
Timo Teras77900a22006-06-26 16:16:12 -0700535 for (i = 0; i < dm_timer_count; i++) {
536 struct omap_dm_timer *timer;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100537
Timo Teras77900a22006-06-26 16:16:12 -0700538 timer = &dm_timers[i];
Timo Teras12583a72006-09-25 12:41:42 +0300539
540 if (!timer->enabled)
541 continue;
542
Timo Teras77900a22006-06-26 16:16:12 -0700543 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
Timo Terasfa4bb622006-09-25 12:41:35 +0300544 OMAP_TIMER_CTRL_ST) {
Timo Teras77900a22006-06-26 16:16:12 -0700545 return 1;
Timo Terasfa4bb622006-09-25 12:41:35 +0300546 }
Tony Lindgren92105bb2005-09-07 17:20:26 +0100547 }
Tony Lindgren92105bb2005-09-07 17:20:26 +0100548 return 0;
549}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700550EXPORT_SYMBOL_GPL(omap_dm_timers_active);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100551
Tony Lindgren11a01862011-03-29 15:54:49 -0700552static int __init omap_dm_timer_init(void)
Timo Teras77900a22006-06-26 16:16:12 -0700553{
554 struct omap_dm_timer *timer;
Tony Lindgren3566fc62009-10-19 15:25:18 -0700555 int i, map_size = SZ_8K; /* Module 4KB + L4 4KB except on omap1 */
Timo Teras77900a22006-06-26 16:16:12 -0700556
Tarun Kanti DebBarma97933d62011-09-20 17:00:17 +0530557 if (!cpu_class_is_omap2())
Timo Teras77900a22006-06-26 16:16:12 -0700558 return -ENODEV;
559
560 spin_lock_init(&dm_timer_lock);
Syed Mohammed, Khasim471b3aa2007-06-21 21:48:07 -0700561
Tarun Kanti DebBarma97933d62011-09-20 17:00:17 +0530562 if (cpu_is_omap24xx()) {
Syed Mohammed, Khasim471b3aa2007-06-21 21:48:07 -0700563 dm_timers = omap2_dm_timers;
Tony Lindgren882c0512010-02-12 12:26:46 -0800564 dm_timer_count = omap2_dm_timer_count;
Santosh Shilimkaraea2a5b2009-05-25 11:08:36 -0700565 dm_source_names = omap2_dm_source_names;
566 dm_source_clocks = omap2_dm_source_clocks;
Syed Mohammed, Khasimce2df9c2007-06-25 22:55:39 -0700567 } else if (cpu_is_omap34xx()) {
568 dm_timers = omap3_dm_timers;
Tony Lindgren882c0512010-02-12 12:26:46 -0800569 dm_timer_count = omap3_dm_timer_count;
Santosh Shilimkaraea2a5b2009-05-25 11:08:36 -0700570 dm_source_names = omap3_dm_source_names;
571 dm_source_clocks = omap3_dm_source_clocks;
Santosh Shilimkar44169072009-05-28 14:16:04 -0700572 } else if (cpu_is_omap44xx()) {
573 dm_timers = omap4_dm_timers;
Tony Lindgren882c0512010-02-12 12:26:46 -0800574 dm_timer_count = omap4_dm_timer_count;
Santosh Shilimkar44169072009-05-28 14:16:04 -0700575 dm_source_names = omap4_dm_source_names;
576 dm_source_clocks = omap4_dm_source_clocks;
Tony Lindgrenee17f112011-09-16 15:44:20 -0700577
578 pr_err("dmtimers disabled for omap4 until hwmod conversion\n");
579 return -ENODEV;
Timo Teras83379c82006-06-26 16:16:23 -0700580 }
Syed Mohammed, Khasim471b3aa2007-06-21 21:48:07 -0700581
582 if (cpu_class_is_omap2())
583 for (i = 0; dm_source_names[i] != NULL; i++)
584 dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
585
Syed Mohammed Khasim56a25642006-12-06 17:14:08 -0800586 if (cpu_is_omap243x())
587 dm_timers[0].phys_base = 0x49018000;
Timo Teras83379c82006-06-26 16:16:23 -0700588
Timo Teras77900a22006-06-26 16:16:12 -0700589 for (i = 0; i < dm_timer_count; i++) {
Timo Teras77900a22006-06-26 16:16:12 -0700590 timer = &dm_timers[i];
Tony Lindgren3566fc62009-10-19 15:25:18 -0700591
592 /* Static mapping, never released */
593 timer->io_base = ioremap(timer->phys_base, map_size);
594 BUG_ON(!timer->io_base);
595
Tony Lindgren140455f2010-02-12 12:26:48 -0800596#ifdef CONFIG_ARCH_OMAP2PLUS
Syed Mohammed, Khasim471b3aa2007-06-21 21:48:07 -0700597 if (cpu_class_is_omap2()) {
598 char clk_name[16];
599 sprintf(clk_name, "gpt%d_ick", i + 1);
600 timer->iclk = clk_get(NULL, clk_name);
601 sprintf(clk_name, "gpt%d_fck", i + 1);
602 timer->fclk = clk_get(NULL, clk_name);
603 }
Tony Lindgren11a01862011-03-29 15:54:49 -0700604
605 /* One or two timers may be set up early for sys_timer */
606 if (sys_timer_reserved & (1 << i)) {
607 timer->reserved = 1;
608 timer->posted = 1;
Tony Lindgrenee17f112011-09-16 15:44:20 -0700609 continue;
Tony Lindgren11a01862011-03-29 15:54:49 -0700610 }
Timo Teras77900a22006-06-26 16:16:12 -0700611#endif
Tony Lindgrenee17f112011-09-16 15:44:20 -0700612 omap_dm_timer_enable(timer);
613 __omap_dm_timer_init_regs(timer);
614 omap_dm_timer_disable(timer);
Timo Teras77900a22006-06-26 16:16:12 -0700615 }
616
617 return 0;
618}
Tony Lindgren11a01862011-03-29 15:54:49 -0700619
620arch_initcall(omap_dm_timer_init);