linux/arch/arm/plat-omap/dmtimer.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/plat-omap/dmtimer.c
   3 *
   4 * OMAP Dual-Mode Timers
   5 *
   6 * Copyright (C) 2005 Nokia Corporation
   7 * OMAP2 support by Juha Yrjola
   8 * API improvements and OMAP2 clock framework support by Timo Teras
   9 *
  10 * Copyright (C) 2009 Texas Instruments
  11 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
  12 *
  13 * This program is free software; you can redistribute it and/or modify it
  14 * under the terms of the GNU General Public License as published by the
  15 * Free Software Foundation; either version 2 of the License, or (at your
  16 * option) any later version.
  17 *
  18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  21 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26 *
  27 * You should have received a copy of the  GNU General Public License along
  28 * with this program; if not, write  to the Free Software Foundation, Inc.,
  29 * 675 Mass Ave, Cambridge, MA 02139, USA.
  30 */
  31
  32#include <linux/init.h>
  33#include <linux/spinlock.h>
  34#include <linux/errno.h>
  35#include <linux/list.h>
  36#include <linux/clk.h>
  37#include <linux/delay.h>
  38#include <linux/io.h>
  39#include <linux/module.h>
  40#include <mach/hardware.h>
  41#include <mach/dmtimer.h>
  42#include <mach/irqs.h>
  43
  44/* register offsets */
  45#define _OMAP_TIMER_ID_OFFSET           0x00
  46#define _OMAP_TIMER_OCP_CFG_OFFSET      0x10
  47#define _OMAP_TIMER_SYS_STAT_OFFSET     0x14
  48#define _OMAP_TIMER_STAT_OFFSET         0x18
  49#define _OMAP_TIMER_INT_EN_OFFSET       0x1c
  50#define _OMAP_TIMER_WAKEUP_EN_OFFSET    0x20
  51#define _OMAP_TIMER_CTRL_OFFSET         0x24
  52#define         OMAP_TIMER_CTRL_GPOCFG          (1 << 14)
  53#define         OMAP_TIMER_CTRL_CAPTMODE        (1 << 13)
  54#define         OMAP_TIMER_CTRL_PT              (1 << 12)
  55#define         OMAP_TIMER_CTRL_TCM_LOWTOHIGH   (0x1 << 8)
  56#define         OMAP_TIMER_CTRL_TCM_HIGHTOLOW   (0x2 << 8)
  57#define         OMAP_TIMER_CTRL_TCM_BOTHEDGES   (0x3 << 8)
  58#define         OMAP_TIMER_CTRL_SCPWM           (1 << 7)
  59#define         OMAP_TIMER_CTRL_CE              (1 << 6) /* compare enable */
  60#define         OMAP_TIMER_CTRL_PRE             (1 << 5) /* prescaler enable */
  61#define         OMAP_TIMER_CTRL_PTV_SHIFT       2 /* prescaler value shift */
  62#define         OMAP_TIMER_CTRL_POSTED          (1 << 2)
  63#define         OMAP_TIMER_CTRL_AR              (1 << 1) /* auto-reload enable */
  64#define         OMAP_TIMER_CTRL_ST              (1 << 0) /* start timer */
  65#define _OMAP_TIMER_COUNTER_OFFSET      0x28
  66#define _OMAP_TIMER_LOAD_OFFSET         0x2c
  67#define _OMAP_TIMER_TRIGGER_OFFSET      0x30
  68#define _OMAP_TIMER_WRITE_PEND_OFFSET   0x34
  69#define         WP_NONE                 0       /* no write pending bit */
  70#define         WP_TCLR                 (1 << 0)
  71#define         WP_TCRR                 (1 << 1)
  72#define         WP_TLDR                 (1 << 2)
  73#define         WP_TTGR                 (1 << 3)
  74#define         WP_TMAR                 (1 << 4)
  75#define         WP_TPIR                 (1 << 5)
  76#define         WP_TNIR                 (1 << 6)
  77#define         WP_TCVR                 (1 << 7)
  78#define         WP_TOCR                 (1 << 8)
  79#define         WP_TOWR                 (1 << 9)
  80#define _OMAP_TIMER_MATCH_OFFSET        0x38
  81#define _OMAP_TIMER_CAPTURE_OFFSET      0x3c
  82#define _OMAP_TIMER_IF_CTRL_OFFSET      0x40
  83#define _OMAP_TIMER_CAPTURE2_OFFSET             0x44    /* TCAR2, 34xx only */
  84#define _OMAP_TIMER_TICK_POS_OFFSET             0x48    /* TPIR, 34xx only */
  85#define _OMAP_TIMER_TICK_NEG_OFFSET             0x4c    /* TNIR, 34xx only */
  86#define _OMAP_TIMER_TICK_COUNT_OFFSET           0x50    /* TCVR, 34xx only */
  87#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET    0x54    /* TOCR, 34xx only */
  88#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET  0x58    /* TOWR, 34xx only */
  89
  90/* register offsets with the write pending bit encoded */
  91#define WPSHIFT                                 16
  92
  93#define OMAP_TIMER_ID_REG                       (_OMAP_TIMER_ID_OFFSET \
  94                                                        | (WP_NONE << WPSHIFT))
  95
  96#define OMAP_TIMER_OCP_CFG_REG                  (_OMAP_TIMER_OCP_CFG_OFFSET \
  97                                                        | (WP_NONE << WPSHIFT))
  98
  99#define OMAP_TIMER_SYS_STAT_REG                 (_OMAP_TIMER_SYS_STAT_OFFSET \
 100                                                        | (WP_NONE << WPSHIFT))
 101
 102#define OMAP_TIMER_STAT_REG                     (_OMAP_TIMER_STAT_OFFSET \
 103                                                        | (WP_NONE << WPSHIFT))
 104
 105#define OMAP_TIMER_INT_EN_REG                   (_OMAP_TIMER_INT_EN_OFFSET \
 106                                                        | (WP_NONE << WPSHIFT))
 107
 108#define OMAP_TIMER_WAKEUP_EN_REG                (_OMAP_TIMER_WAKEUP_EN_OFFSET \
 109                                                        | (WP_NONE << WPSHIFT))
 110
 111#define OMAP_TIMER_CTRL_REG                     (_OMAP_TIMER_CTRL_OFFSET \
 112                                                        | (WP_TCLR << WPSHIFT))
 113
 114#define OMAP_TIMER_COUNTER_REG                  (_OMAP_TIMER_COUNTER_OFFSET \
 115                                                        | (WP_TCRR << WPSHIFT))
 116
 117#define OMAP_TIMER_LOAD_REG                     (_OMAP_TIMER_LOAD_OFFSET \
 118                                                        | (WP_TLDR << WPSHIFT))
 119
 120#define OMAP_TIMER_TRIGGER_REG                  (_OMAP_TIMER_TRIGGER_OFFSET \
 121                                                        | (WP_TTGR << WPSHIFT))
 122
 123#define OMAP_TIMER_WRITE_PEND_REG               (_OMAP_TIMER_WRITE_PEND_OFFSET \
 124                                                        | (WP_NONE << WPSHIFT))
 125
 126#define OMAP_TIMER_MATCH_REG                    (_OMAP_TIMER_MATCH_OFFSET \
 127                                                        | (WP_TMAR << WPSHIFT))
 128
 129#define OMAP_TIMER_CAPTURE_REG                  (_OMAP_TIMER_CAPTURE_OFFSET \
 130                                                        | (WP_NONE << WPSHIFT))
 131
 132#define OMAP_TIMER_IF_CTRL_REG                  (_OMAP_TIMER_IF_CTRL_OFFSET \
 133                                                        | (WP_NONE << WPSHIFT))
 134
 135#define OMAP_TIMER_CAPTURE2_REG                 (_OMAP_TIMER_CAPTURE2_OFFSET \
 136                                                        | (WP_NONE << WPSHIFT))
 137
 138#define OMAP_TIMER_TICK_POS_REG                 (_OMAP_TIMER_TICK_POS_OFFSET \
 139                                                        | (WP_TPIR << WPSHIFT))
 140
 141#define OMAP_TIMER_TICK_NEG_REG                 (_OMAP_TIMER_TICK_NEG_OFFSET \
 142                                                        | (WP_TNIR << WPSHIFT))
 143
 144#define OMAP_TIMER_TICK_COUNT_REG               (_OMAP_TIMER_TICK_COUNT_OFFSET \
 145                                                        | (WP_TCVR << WPSHIFT))
 146
 147#define OMAP_TIMER_TICK_INT_MASK_SET_REG                                \
 148                (_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT))
 149
 150#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG                              \
 151                (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
 152
 153struct omap_dm_timer {
 154        unsigned long phys_base;
 155        int irq;
 156#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
 157                        defined(CONFIG_ARCH_OMAP4)
 158        struct clk *iclk, *fclk;
 159#endif
 160        void __iomem *io_base;
 161        unsigned reserved:1;
 162        unsigned enabled:1;
 163        unsigned posted:1;
 164};
 165
 166#ifdef CONFIG_ARCH_OMAP1
 167
 168#define omap_dm_clk_enable(x)
 169#define omap_dm_clk_disable(x)
 170#define omap2_dm_timers                 NULL
 171#define omap2_dm_source_names           NULL
 172#define omap2_dm_source_clocks          NULL
 173#define omap3_dm_timers                 NULL
 174#define omap3_dm_source_names           NULL
 175#define omap3_dm_source_clocks          NULL
 176#define omap4_dm_timers                 NULL
 177#define omap4_dm_source_names           NULL
 178#define omap4_dm_source_clocks          NULL
 179
 180static struct omap_dm_timer omap1_dm_timers[] = {
 181        { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
 182        { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 },
 183        { .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 },
 184        { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 },
 185        { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 },
 186        { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 },
 187        { .phys_base = 0xfffb7400, .irq = INT_1610_GPTIMER7 },
 188        { .phys_base = 0xfffbd400, .irq = INT_1610_GPTIMER8 },
 189};
 190
 191static const int dm_timer_count = ARRAY_SIZE(omap1_dm_timers);
 192
 193#elif defined(CONFIG_ARCH_OMAP2)
 194
 195#define omap_dm_clk_enable(x)           clk_enable(x)
 196#define omap_dm_clk_disable(x)          clk_disable(x)
 197#define omap1_dm_timers                 NULL
 198#define omap3_dm_timers                 NULL
 199#define omap3_dm_source_names           NULL
 200#define omap3_dm_source_clocks          NULL
 201#define omap4_dm_timers                 NULL
 202#define omap4_dm_source_names           NULL
 203#define omap4_dm_source_clocks          NULL
 204
 205static struct omap_dm_timer omap2_dm_timers[] = {
 206        { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
 207        { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
 208        { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
 209        { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
 210        { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
 211        { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
 212        { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
 213        { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
 214        { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
 215        { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
 216        { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
 217        { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
 218};
 219
 220static const char *omap2_dm_source_names[] __initdata = {
 221        "sys_ck",
 222        "func_32k_ck",
 223        "alt_ck",
 224        NULL
 225};
 226
 227static struct clk *omap2_dm_source_clocks[3];
 228static const int dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
 229
 230#elif defined(CONFIG_ARCH_OMAP3)
 231
 232#define omap_dm_clk_enable(x)           clk_enable(x)
 233#define omap_dm_clk_disable(x)          clk_disable(x)
 234#define omap1_dm_timers                 NULL
 235#define omap2_dm_timers                 NULL
 236#define omap2_dm_source_names           NULL
 237#define omap2_dm_source_clocks          NULL
 238#define omap4_dm_timers                 NULL
 239#define omap4_dm_source_names           NULL
 240#define omap4_dm_source_clocks          NULL
 241
 242static struct omap_dm_timer omap3_dm_timers[] = {
 243        { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
 244        { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
 245        { .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
 246        { .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
 247        { .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
 248        { .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
 249        { .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
 250        { .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
 251        { .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
 252        { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
 253        { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
 254        { .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
 255};
 256
 257static const char *omap3_dm_source_names[] __initdata = {
 258        "sys_ck",
 259        "omap_32k_fck",
 260        NULL
 261};
 262
 263static struct clk *omap3_dm_source_clocks[2];
 264static const int dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
 265
 266#elif defined(CONFIG_ARCH_OMAP4)
 267
 268#define omap_dm_clk_enable(x)           clk_enable(x)
 269#define omap_dm_clk_disable(x)          clk_disable(x)
 270#define omap1_dm_timers                 NULL
 271#define omap2_dm_timers                 NULL
 272#define omap2_dm_source_names           NULL
 273#define omap2_dm_source_clocks          NULL
 274#define omap3_dm_timers                 NULL
 275#define omap3_dm_source_names           NULL
 276#define omap3_dm_source_clocks          NULL
 277
 278static struct omap_dm_timer omap4_dm_timers[] = {
 279        { .phys_base = 0x4a318000, .irq = INT_44XX_GPTIMER1 },
 280        { .phys_base = 0x48032000, .irq = INT_44XX_GPTIMER2 },
 281        { .phys_base = 0x48034000, .irq = INT_44XX_GPTIMER3 },
 282        { .phys_base = 0x48036000, .irq = INT_44XX_GPTIMER4 },
 283        { .phys_base = 0x40138000, .irq = INT_44XX_GPTIMER5 },
 284        { .phys_base = 0x4013a000, .irq = INT_44XX_GPTIMER6 },
 285        { .phys_base = 0x4013a000, .irq = INT_44XX_GPTIMER7 },
 286        { .phys_base = 0x4013e000, .irq = INT_44XX_GPTIMER8 },
 287        { .phys_base = 0x4803e000, .irq = INT_44XX_GPTIMER9 },
 288        { .phys_base = 0x48086000, .irq = INT_44XX_GPTIMER10 },
 289        { .phys_base = 0x48088000, .irq = INT_44XX_GPTIMER11 },
 290        { .phys_base = 0x4a320000, .irq = INT_44XX_GPTIMER12 },
 291};
 292static const char *omap4_dm_source_names[] __initdata = {
 293        "sys_ck",
 294        "omap_32k_fck",
 295        NULL
 296};
 297static struct clk *omap4_dm_source_clocks[2];
 298static const int dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
 299
 300#else
 301
 302#error OMAP architecture not supported!
 303
 304#endif
 305
 306static struct omap_dm_timer *dm_timers;
 307static const char **dm_source_names;
 308static struct clk **dm_source_clocks;
 309
 310static spinlock_t dm_timer_lock;
 311
 312/*
 313 * Reads timer registers in posted and non-posted mode. The posted mode bit
 314 * is encoded in reg. Note that in posted mode write pending bit must be
 315 * checked. Otherwise a read of a non completed write will produce an error.
 316 */
 317static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 318{
 319        if (timer->posted)
 320                while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
 321                                & (reg >> WPSHIFT))
 322                        cpu_relax();
 323        return readl(timer->io_base + (reg & 0xff));
 324}
 325
 326/*
 327 * Writes timer registers in posted and non-posted mode. The posted mode bit
 328 * is encoded in reg. Note that in posted mode the write pending bit must be
 329 * checked. Otherwise a write on a register which has a pending write will be
 330 * lost.
 331 */
 332static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 333                                                u32 value)
 334{
 335        if (timer->posted)
 336                while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
 337                                & (reg >> WPSHIFT))
 338                        cpu_relax();
 339        writel(value, timer->io_base + (reg & 0xff));
 340}
 341
 342static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 343{
 344        int c;
 345
 346        c = 0;
 347        while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) {
 348                c++;
 349                if (c > 100000) {
 350                        printk(KERN_ERR "Timer failed to reset\n");
 351                        return;
 352                }
 353        }
 354}
 355
 356static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 357{
 358        u32 l;
 359
 360        if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
 361                omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 362                omap_dm_timer_wait_for_reset(timer);
 363        }
 364        omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
 365
 366        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG);
 367        l |= 0x02 << 3;  /* Set to smart-idle mode */
 368        l |= 0x2 << 8;   /* Set clock activity to perserve f-clock on idle */
 369
 370        /*
 371         * Enable wake-up on OMAP2 CPUs.
 372         */
 373        if (cpu_class_is_omap2())
 374                l |= 1 << 2;
 375        omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l);
 376
 377        /* Match hardware reset default of posted mode */
 378        omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
 379                        OMAP_TIMER_CTRL_POSTED);
 380        timer->posted = 1;
 381}
 382
 383static void omap_dm_timer_prepare(struct omap_dm_timer *timer)
 384{
 385        omap_dm_timer_enable(timer);
 386        omap_dm_timer_reset(timer);
 387}
 388
 389struct omap_dm_timer *omap_dm_timer_request(void)
 390{
 391        struct omap_dm_timer *timer = NULL;
 392        unsigned long flags;
 393        int i;
 394
 395        spin_lock_irqsave(&dm_timer_lock, flags);
 396        for (i = 0; i < dm_timer_count; i++) {
 397                if (dm_timers[i].reserved)
 398                        continue;
 399
 400                timer = &dm_timers[i];
 401                timer->reserved = 1;
 402                break;
 403        }
 404        spin_unlock_irqrestore(&dm_timer_lock, flags);
 405
 406        if (timer != NULL)
 407                omap_dm_timer_prepare(timer);
 408
 409        return timer;
 410}
 411EXPORT_SYMBOL_GPL(omap_dm_timer_request);
 412
 413struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 414{
 415        struct omap_dm_timer *timer;
 416        unsigned long flags;
 417
 418        spin_lock_irqsave(&dm_timer_lock, flags);
 419        if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
 420                spin_unlock_irqrestore(&dm_timer_lock, flags);
 421                printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
 422                       __FILE__, __LINE__, __func__, id);
 423                dump_stack();
 424                return NULL;
 425        }
 426
 427        timer = &dm_timers[id-1];
 428        timer->reserved = 1;
 429        spin_unlock_irqrestore(&dm_timer_lock, flags);
 430
 431        omap_dm_timer_prepare(timer);
 432
 433        return timer;
 434}
 435EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 436
 437void omap_dm_timer_free(struct omap_dm_timer *timer)
 438{
 439        omap_dm_timer_enable(timer);
 440        omap_dm_timer_reset(timer);
 441        omap_dm_timer_disable(timer);
 442
 443        WARN_ON(!timer->reserved);
 444        timer->reserved = 0;
 445}
 446EXPORT_SYMBOL_GPL(omap_dm_timer_free);
 447
 448void omap_dm_timer_enable(struct omap_dm_timer *timer)
 449{
 450        if (timer->enabled)
 451                return;
 452
 453        omap_dm_clk_enable(timer->fclk);
 454        omap_dm_clk_enable(timer->iclk);
 455
 456        timer->enabled = 1;
 457}
 458EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
 459
 460void omap_dm_timer_disable(struct omap_dm_timer *timer)
 461{
 462        if (!timer->enabled)
 463                return;
 464
 465        omap_dm_clk_disable(timer->iclk);
 466        omap_dm_clk_disable(timer->fclk);
 467
 468        timer->enabled = 0;
 469}
 470EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
 471
 472int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
 473{
 474        return timer->irq;
 475}
 476EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
 477
 478#if defined(CONFIG_ARCH_OMAP1)
 479
 480/**
 481 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
 482 * @inputmask: current value of idlect mask
 483 */
 484__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 485{
 486        int i;
 487
 488        /* If ARMXOR cannot be idled this function call is unnecessary */
 489        if (!(inputmask & (1 << 1)))
 490                return inputmask;
 491
 492        /* If any active timer is using ARMXOR return modified mask */
 493        for (i = 0; i < dm_timer_count; i++) {
 494                u32 l;
 495
 496                l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
 497                if (l & OMAP_TIMER_CTRL_ST) {
 498                        if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
 499                                inputmask &= ~(1 << 1);
 500                        else
 501                                inputmask &= ~(1 << 2);
 502                }
 503        }
 504
 505        return inputmask;
 506}
 507EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 508
 509#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
 510                                defined(CONFIG_ARCH_OMAP4)
 511
 512struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
 513{
 514        return timer->fclk;
 515}
 516EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
 517
 518__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 519{
 520        BUG();
 521
 522        return 0;
 523}
 524EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 525
 526#endif
 527
 528void omap_dm_timer_trigger(struct omap_dm_timer *timer)
 529{
 530        omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 531}
 532EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
 533
 534void omap_dm_timer_start(struct omap_dm_timer *timer)
 535{
 536        u32 l;
 537
 538        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 539        if (!(l & OMAP_TIMER_CTRL_ST)) {
 540                l |= OMAP_TIMER_CTRL_ST;
 541                omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 542        }
 543}
 544EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 545
 546void omap_dm_timer_stop(struct omap_dm_timer *timer)
 547{
 548        u32 l;
 549
 550        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 551        if (l & OMAP_TIMER_CTRL_ST) {
 552                l &= ~0x1;
 553                omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 554        }
 555}
 556EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 557
 558#ifdef CONFIG_ARCH_OMAP1
 559
 560int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 561{
 562        int n = (timer - dm_timers) << 1;
 563        u32 l;
 564
 565        l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
 566        l |= source << n;
 567        omap_writel(l, MOD_CONF_CTRL_1);
 568
 569        return 0;
 570}
 571EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 572
 573#else
 574
 575int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 576{
 577        int ret = -EINVAL;
 578
 579        if (source < 0 || source >= 3)
 580                return -EINVAL;
 581
 582        clk_disable(timer->fclk);
 583        ret = clk_set_parent(timer->fclk, dm_source_clocks[source]);
 584        clk_enable(timer->fclk);
 585
 586        /*
 587         * When the functional clock disappears, too quick writes seem
 588         * to cause an abort. XXX Is this still necessary?
 589         */
 590        __delay(150000);
 591
 592        return ret;
 593}
 594EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 595
 596#endif
 597
 598void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 599                            unsigned int load)
 600{
 601        u32 l;
 602
 603        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 604        if (autoreload)
 605                l |= OMAP_TIMER_CTRL_AR;
 606        else
 607                l &= ~OMAP_TIMER_CTRL_AR;
 608        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 609        omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 610
 611        omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 612}
 613EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
 614
 615/* Optimized set_load which removes costly spin wait in timer_start */
 616void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 617                            unsigned int load)
 618{
 619        u32 l;
 620
 621        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 622        if (autoreload) {
 623                l |= OMAP_TIMER_CTRL_AR;
 624                omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 625        } else {
 626                l &= ~OMAP_TIMER_CTRL_AR;
 627        }
 628        l |= OMAP_TIMER_CTRL_ST;
 629
 630        omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, load);
 631        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 632}
 633EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 634
 635void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 636                             unsigned int match)
 637{
 638        u32 l;
 639
 640        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 641        if (enable)
 642                l |= OMAP_TIMER_CTRL_CE;
 643        else
 644                l &= ~OMAP_TIMER_CTRL_CE;
 645        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 646        omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
 647}
 648EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
 649
 650void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 651                           int toggle, int trigger)
 652{
 653        u32 l;
 654
 655        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 656        l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
 657               OMAP_TIMER_CTRL_PT | (0x03 << 10));
 658        if (def_on)
 659                l |= OMAP_TIMER_CTRL_SCPWM;
 660        if (toggle)
 661                l |= OMAP_TIMER_CTRL_PT;
 662        l |= trigger << 10;
 663        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 664}
 665EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
 666
 667void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 668{
 669        u32 l;
 670
 671        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 672        l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
 673        if (prescaler >= 0x00 && prescaler <= 0x07) {
 674                l |= OMAP_TIMER_CTRL_PRE;
 675                l |= prescaler << 2;
 676        }
 677        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 678}
 679EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
 680
 681void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
 682                                  unsigned int value)
 683{
 684        omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
 685        omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value);
 686}
 687EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 688
 689unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 690{
 691        unsigned int l;
 692
 693        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
 694
 695        return l;
 696}
 697EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
 698
 699void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 700{
 701        omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
 702}
 703EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
 704
 705unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 706{
 707        unsigned int l;
 708
 709        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
 710
 711        return l;
 712}
 713EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 714
 715void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
 716{
 717        omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
 718}
 719EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 720
 721int omap_dm_timers_active(void)
 722{
 723        int i;
 724
 725        for (i = 0; i < dm_timer_count; i++) {
 726                struct omap_dm_timer *timer;
 727
 728                timer = &dm_timers[i];
 729
 730                if (!timer->enabled)
 731                        continue;
 732
 733                if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
 734                    OMAP_TIMER_CTRL_ST) {
 735                        return 1;
 736                }
 737        }
 738        return 0;
 739}
 740EXPORT_SYMBOL_GPL(omap_dm_timers_active);
 741
 742int __init omap_dm_timer_init(void)
 743{
 744        struct omap_dm_timer *timer;
 745        int i;
 746
 747        if (!(cpu_is_omap16xx() || cpu_class_is_omap2()))
 748                return -ENODEV;
 749
 750        spin_lock_init(&dm_timer_lock);
 751
 752        if (cpu_class_is_omap1())
 753                dm_timers = omap1_dm_timers;
 754        else if (cpu_is_omap24xx()) {
 755                dm_timers = omap2_dm_timers;
 756                dm_source_names = omap2_dm_source_names;
 757                dm_source_clocks = omap2_dm_source_clocks;
 758        } else if (cpu_is_omap34xx()) {
 759                dm_timers = omap3_dm_timers;
 760                dm_source_names = omap3_dm_source_names;
 761                dm_source_clocks = omap3_dm_source_clocks;
 762        } else if (cpu_is_omap44xx()) {
 763                dm_timers = omap4_dm_timers;
 764                dm_source_names = omap4_dm_source_names;
 765                dm_source_clocks = omap4_dm_source_clocks;
 766        }
 767
 768        if (cpu_class_is_omap2())
 769                for (i = 0; dm_source_names[i] != NULL; i++)
 770                        dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
 771
 772        if (cpu_is_omap243x())
 773                dm_timers[0].phys_base = 0x49018000;
 774
 775        for (i = 0; i < dm_timer_count; i++) {
 776                timer = &dm_timers[i];
 777                if (cpu_class_is_omap1())
 778                        timer->io_base = OMAP1_IO_ADDRESS(timer->phys_base);
 779                else
 780                        timer->io_base = OMAP2_IO_ADDRESS(timer->phys_base);
 781#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
 782                                        defined(CONFIG_ARCH_OMAP4)
 783                if (cpu_class_is_omap2()) {
 784                        char clk_name[16];
 785                        sprintf(clk_name, "gpt%d_ick", i + 1);
 786                        timer->iclk = clk_get(NULL, clk_name);
 787                        sprintf(clk_name, "gpt%d_fck", i + 1);
 788                        timer->fclk = clk_get(NULL, clk_name);
 789                }
 790#endif
 791        }
 792
 793        return 0;
 794}
 795