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) 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 *
  12 * Copyright (C) 2005 Nokia Corporation
  13 * OMAP2 support by Juha Yrjola
  14 * API improvements and OMAP2 clock framework support by Timo Teras
  15 *
  16 * Copyright (C) 2009 Texas Instruments
  17 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
  18 *
  19 * 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/clk.h>
  39#include <linux/module.h>
  40#include <linux/io.h>
  41#include <linux/device.h>
  42#include <linux/err.h>
  43#include <linux/pm_runtime.h>
  44#include <linux/of.h>
  45#include <linux/of_device.h>
  46#include <linux/platform_device.h>
  47#include <linux/platform_data/dmtimer-omap.h>
  48
  49#include <plat/dmtimer.h>
  50
  51static u32 omap_reserved_systimers;
  52static LIST_HEAD(omap_timer_list);
  53static DEFINE_SPINLOCK(dm_timer_lock);
  54
  55/**
  56 * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
  57 * @timer:      timer pointer over which read operation to perform
  58 * @reg:        lowest byte holds the register offset
  59 *
  60 * The posted mode bit is encoded in reg. Note that in posted mode write
  61 * pending bit must be checked. Otherwise a read of a non completed write
  62 * will produce an error.
  63 */
  64static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
  65{
  66        WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
  67        return __omap_dm_timer_read(timer, reg, timer->posted);
  68}
  69
  70/**
  71 * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
  72 * @timer:      timer pointer over which write operation is to perform
  73 * @reg:        lowest byte holds the register offset
  74 * @value:      data to write into the register
  75 *
  76 * The posted mode bit is encoded in reg. Note that in posted mode the write
  77 * pending bit must be checked. Otherwise a write on a register which has a
  78 * pending write will be lost.
  79 */
  80static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
  81                                                u32 value)
  82{
  83        WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
  84        __omap_dm_timer_write(timer, reg, value, timer->posted);
  85}
  86
  87static void omap_timer_restore_context(struct omap_dm_timer *timer)
  88{
  89        omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
  90                                timer->context.twer);
  91        omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
  92                                timer->context.tcrr);
  93        omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
  94                                timer->context.tldr);
  95        omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
  96                                timer->context.tmar);
  97        omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
  98                                timer->context.tsicr);
  99        __raw_writel(timer->context.tier, timer->irq_ena);
 100        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
 101                                timer->context.tclr);
 102}
 103
 104static int omap_dm_timer_reset(struct omap_dm_timer *timer)
 105{
 106        u32 l, timeout = 100000;
 107
 108        if (timer->revision != 1)
 109                return -EINVAL;
 110
 111        omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 112
 113        do {
 114                l = __omap_dm_timer_read(timer,
 115                                         OMAP_TIMER_V1_SYS_STAT_OFFSET, 0);
 116        } while (!l && timeout--);
 117
 118        if (!timeout) {
 119                dev_err(&timer->pdev->dev, "Timer failed to reset\n");
 120                return -ETIMEDOUT;
 121        }
 122
 123        /* Configure timer for smart-idle mode */
 124        l = __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0);
 125        l |= 0x2 << 0x3;
 126        __omap_dm_timer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, l, 0);
 127
 128        timer->posted = 0;
 129
 130        return 0;
 131}
 132
 133static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
 134{
 135        int rc;
 136
 137        /*
 138         * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
 139         * do not call clk_get() for these devices.
 140         */
 141        if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
 142                timer->fclk = clk_get(&timer->pdev->dev, "fck");
 143                if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
 144                        timer->fclk = NULL;
 145                        dev_err(&timer->pdev->dev, ": No fclk handle.\n");
 146                        return -EINVAL;
 147                }
 148        }
 149
 150        omap_dm_timer_enable(timer);
 151
 152        if (timer->capability & OMAP_TIMER_NEEDS_RESET) {
 153                rc = omap_dm_timer_reset(timer);
 154                if (rc) {
 155                        omap_dm_timer_disable(timer);
 156                        return rc;
 157                }
 158        }
 159
 160        __omap_dm_timer_enable_posted(timer);
 161        omap_dm_timer_disable(timer);
 162
 163        return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
 164}
 165
 166static inline u32 omap_dm_timer_reserved_systimer(int id)
 167{
 168        return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0;
 169}
 170
 171int omap_dm_timer_reserve_systimer(int id)
 172{
 173        if (omap_dm_timer_reserved_systimer(id))
 174                return -ENODEV;
 175
 176        omap_reserved_systimers |= (1 << (id - 1));
 177
 178        return 0;
 179}
 180
 181struct omap_dm_timer *omap_dm_timer_request(void)
 182{
 183        struct omap_dm_timer *timer = NULL, *t;
 184        unsigned long flags;
 185        int ret = 0;
 186
 187        spin_lock_irqsave(&dm_timer_lock, flags);
 188        list_for_each_entry(t, &omap_timer_list, node) {
 189                if (t->reserved)
 190                        continue;
 191
 192                timer = t;
 193                timer->reserved = 1;
 194                break;
 195        }
 196        spin_unlock_irqrestore(&dm_timer_lock, flags);
 197
 198        if (timer) {
 199                ret = omap_dm_timer_prepare(timer);
 200                if (ret) {
 201                        timer->reserved = 0;
 202                        timer = NULL;
 203                }
 204        }
 205
 206        if (!timer)
 207                pr_debug("%s: timer request failed!\n", __func__);
 208
 209        return timer;
 210}
 211EXPORT_SYMBOL_GPL(omap_dm_timer_request);
 212
 213struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 214{
 215        struct omap_dm_timer *timer = NULL, *t;
 216        unsigned long flags;
 217        int ret = 0;
 218
 219        /* Requesting timer by ID is not supported when device tree is used */
 220        if (of_have_populated_dt()) {
 221                pr_warn("%s: Please use omap_dm_timer_request_by_cap()\n",
 222                        __func__);
 223                return NULL;
 224        }
 225
 226        spin_lock_irqsave(&dm_timer_lock, flags);
 227        list_for_each_entry(t, &omap_timer_list, node) {
 228                if (t->pdev->id == id && !t->reserved) {
 229                        timer = t;
 230                        timer->reserved = 1;
 231                        break;
 232                }
 233        }
 234        spin_unlock_irqrestore(&dm_timer_lock, flags);
 235
 236        if (timer) {
 237                ret = omap_dm_timer_prepare(timer);
 238                if (ret) {
 239                        timer->reserved = 0;
 240                        timer = NULL;
 241                }
 242        }
 243
 244        if (!timer)
 245                pr_debug("%s: timer%d request failed!\n", __func__, id);
 246
 247        return timer;
 248}
 249EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 250
 251/**
 252 * omap_dm_timer_request_by_cap - Request a timer by capability
 253 * @cap:        Bit mask of capabilities to match
 254 *
 255 * Find a timer based upon capabilities bit mask. Callers of this function
 256 * should use the definitions found in the plat/dmtimer.h file under the
 257 * comment "timer capabilities used in hwmod database". Returns pointer to
 258 * timer handle on success and a NULL pointer on failure.
 259 */
 260struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap)
 261{
 262        struct omap_dm_timer *timer = NULL, *t;
 263        unsigned long flags;
 264
 265        if (!cap)
 266                return NULL;
 267
 268        spin_lock_irqsave(&dm_timer_lock, flags);
 269        list_for_each_entry(t, &omap_timer_list, node) {
 270                if ((!t->reserved) && ((t->capability & cap) == cap)) {
 271                        /*
 272                         * If timer is not NULL, we have already found one timer
 273                         * but it was not an exact match because it had more
 274                         * capabilites that what was required. Therefore,
 275                         * unreserve the last timer found and see if this one
 276                         * is a better match.
 277                         */
 278                        if (timer)
 279                                timer->reserved = 0;
 280
 281                        timer = t;
 282                        timer->reserved = 1;
 283
 284                        /* Exit loop early if we find an exact match */
 285                        if (t->capability == cap)
 286                                break;
 287                }
 288        }
 289        spin_unlock_irqrestore(&dm_timer_lock, flags);
 290
 291        if (timer && omap_dm_timer_prepare(timer)) {
 292                timer->reserved = 0;
 293                timer = NULL;
 294        }
 295
 296        if (!timer)
 297                pr_debug("%s: timer request failed!\n", __func__);
 298
 299        return timer;
 300}
 301EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap);
 302
 303int omap_dm_timer_free(struct omap_dm_timer *timer)
 304{
 305        if (unlikely(!timer))
 306                return -EINVAL;
 307
 308        clk_put(timer->fclk);
 309
 310        WARN_ON(!timer->reserved);
 311        timer->reserved = 0;
 312        return 0;
 313}
 314EXPORT_SYMBOL_GPL(omap_dm_timer_free);
 315
 316void omap_dm_timer_enable(struct omap_dm_timer *timer)
 317{
 318        pm_runtime_get_sync(&timer->pdev->dev);
 319}
 320EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
 321
 322void omap_dm_timer_disable(struct omap_dm_timer *timer)
 323{
 324        pm_runtime_put_sync(&timer->pdev->dev);
 325}
 326EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
 327
 328int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
 329{
 330        if (timer)
 331                return timer->irq;
 332        return -EINVAL;
 333}
 334EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
 335
 336#if defined(CONFIG_ARCH_OMAP1)
 337#include <mach/hardware.h>
 338/**
 339 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
 340 * @inputmask: current value of idlect mask
 341 */
 342__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 343{
 344        int i = 0;
 345        struct omap_dm_timer *timer = NULL;
 346        unsigned long flags;
 347
 348        /* If ARMXOR cannot be idled this function call is unnecessary */
 349        if (!(inputmask & (1 << 1)))
 350                return inputmask;
 351
 352        /* If any active timer is using ARMXOR return modified mask */
 353        spin_lock_irqsave(&dm_timer_lock, flags);
 354        list_for_each_entry(timer, &omap_timer_list, node) {
 355                u32 l;
 356
 357                l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 358                if (l & OMAP_TIMER_CTRL_ST) {
 359                        if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
 360                                inputmask &= ~(1 << 1);
 361                        else
 362                                inputmask &= ~(1 << 2);
 363                }
 364                i++;
 365        }
 366        spin_unlock_irqrestore(&dm_timer_lock, flags);
 367
 368        return inputmask;
 369}
 370EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 371
 372#else
 373
 374struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
 375{
 376        if (timer)
 377                return timer->fclk;
 378        return NULL;
 379}
 380EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
 381
 382__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 383{
 384        BUG();
 385
 386        return 0;
 387}
 388EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 389
 390#endif
 391
 392int omap_dm_timer_trigger(struct omap_dm_timer *timer)
 393{
 394        if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
 395                pr_err("%s: timer not available or enabled.\n", __func__);
 396                return -EINVAL;
 397        }
 398
 399        omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 400        return 0;
 401}
 402EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
 403
 404int omap_dm_timer_start(struct omap_dm_timer *timer)
 405{
 406        u32 l;
 407
 408        if (unlikely(!timer))
 409                return -EINVAL;
 410
 411        omap_dm_timer_enable(timer);
 412
 413        if (!(timer->capability & OMAP_TIMER_ALWON)) {
 414                if (timer->get_context_loss_count &&
 415                        timer->get_context_loss_count(&timer->pdev->dev) !=
 416                                timer->ctx_loss_count)
 417                        omap_timer_restore_context(timer);
 418        }
 419
 420        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 421        if (!(l & OMAP_TIMER_CTRL_ST)) {
 422                l |= OMAP_TIMER_CTRL_ST;
 423                omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 424        }
 425
 426        /* Save the context */
 427        timer->context.tclr = l;
 428        return 0;
 429}
 430EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 431
 432int omap_dm_timer_stop(struct omap_dm_timer *timer)
 433{
 434        unsigned long rate = 0;
 435
 436        if (unlikely(!timer))
 437                return -EINVAL;
 438
 439        if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
 440                rate = clk_get_rate(timer->fclk);
 441
 442        __omap_dm_timer_stop(timer, timer->posted, rate);
 443
 444        if (!(timer->capability & OMAP_TIMER_ALWON)) {
 445                if (timer->get_context_loss_count)
 446                        timer->ctx_loss_count =
 447                                timer->get_context_loss_count(&timer->pdev->dev);
 448        }
 449
 450        /*
 451         * Since the register values are computed and written within
 452         * __omap_dm_timer_stop, we need to use read to retrieve the
 453         * context.
 454         */
 455        timer->context.tclr =
 456                        omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 457        omap_dm_timer_disable(timer);
 458        return 0;
 459}
 460EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 461
 462int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 463{
 464        int ret;
 465        char *parent_name = NULL;
 466        struct clk *parent;
 467        struct dmtimer_platform_data *pdata;
 468
 469        if (unlikely(!timer))
 470                return -EINVAL;
 471
 472        pdata = timer->pdev->dev.platform_data;
 473
 474        if (source < 0 || source >= 3)
 475                return -EINVAL;
 476
 477        /*
 478         * FIXME: Used for OMAP1 devices only because they do not currently
 479         * use the clock framework to set the parent clock. To be removed
 480         * once OMAP1 migrated to using clock framework for dmtimers
 481         */
 482        if (pdata && pdata->set_timer_src)
 483                return pdata->set_timer_src(timer->pdev, source);
 484
 485        if (!timer->fclk)
 486                return -EINVAL;
 487
 488        switch (source) {
 489        case OMAP_TIMER_SRC_SYS_CLK:
 490                parent_name = "timer_sys_ck";
 491                break;
 492
 493        case OMAP_TIMER_SRC_32_KHZ:
 494                parent_name = "timer_32k_ck";
 495                break;
 496
 497        case OMAP_TIMER_SRC_EXT_CLK:
 498                parent_name = "timer_ext_ck";
 499                break;
 500        }
 501
 502        parent = clk_get(&timer->pdev->dev, parent_name);
 503        if (IS_ERR_OR_NULL(parent)) {
 504                pr_err("%s: %s not found\n", __func__, parent_name);
 505                return -EINVAL;
 506        }
 507
 508        ret = clk_set_parent(timer->fclk, parent);
 509        if (IS_ERR_VALUE(ret))
 510                pr_err("%s: failed to set %s as parent\n", __func__,
 511                        parent_name);
 512
 513        clk_put(parent);
 514
 515        return ret;
 516}
 517EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 518
 519int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 520                            unsigned int load)
 521{
 522        u32 l;
 523
 524        if (unlikely(!timer))
 525                return -EINVAL;
 526
 527        omap_dm_timer_enable(timer);
 528        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 529        if (autoreload)
 530                l |= OMAP_TIMER_CTRL_AR;
 531        else
 532                l &= ~OMAP_TIMER_CTRL_AR;
 533        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 534        omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 535
 536        omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 537        /* Save the context */
 538        timer->context.tclr = l;
 539        timer->context.tldr = load;
 540        omap_dm_timer_disable(timer);
 541        return 0;
 542}
 543EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
 544
 545/* Optimized set_load which removes costly spin wait in timer_start */
 546int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 547                            unsigned int load)
 548{
 549        u32 l;
 550
 551        if (unlikely(!timer))
 552                return -EINVAL;
 553
 554        omap_dm_timer_enable(timer);
 555
 556        if (!(timer->capability & OMAP_TIMER_ALWON)) {
 557                if (timer->get_context_loss_count &&
 558                        timer->get_context_loss_count(&timer->pdev->dev) !=
 559                                timer->ctx_loss_count)
 560                        omap_timer_restore_context(timer);
 561        }
 562
 563        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 564        if (autoreload) {
 565                l |= OMAP_TIMER_CTRL_AR;
 566                omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 567        } else {
 568                l &= ~OMAP_TIMER_CTRL_AR;
 569        }
 570        l |= OMAP_TIMER_CTRL_ST;
 571
 572        __omap_dm_timer_load_start(timer, l, load, timer->posted);
 573
 574        /* Save the context */
 575        timer->context.tclr = l;
 576        timer->context.tldr = load;
 577        timer->context.tcrr = load;
 578        return 0;
 579}
 580EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 581
 582int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 583                             unsigned int match)
 584{
 585        u32 l;
 586
 587        if (unlikely(!timer))
 588                return -EINVAL;
 589
 590        omap_dm_timer_enable(timer);
 591        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 592        if (enable)
 593                l |= OMAP_TIMER_CTRL_CE;
 594        else
 595                l &= ~OMAP_TIMER_CTRL_CE;
 596        omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
 597        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 598
 599        /* Save the context */
 600        timer->context.tclr = l;
 601        timer->context.tmar = match;
 602        omap_dm_timer_disable(timer);
 603        return 0;
 604}
 605EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
 606
 607int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 608                           int toggle, int trigger)
 609{
 610        u32 l;
 611
 612        if (unlikely(!timer))
 613                return -EINVAL;
 614
 615        omap_dm_timer_enable(timer);
 616        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 617        l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
 618               OMAP_TIMER_CTRL_PT | (0x03 << 10));
 619        if (def_on)
 620                l |= OMAP_TIMER_CTRL_SCPWM;
 621        if (toggle)
 622                l |= OMAP_TIMER_CTRL_PT;
 623        l |= trigger << 10;
 624        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 625
 626        /* Save the context */
 627        timer->context.tclr = l;
 628        omap_dm_timer_disable(timer);
 629        return 0;
 630}
 631EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
 632
 633int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 634{
 635        u32 l;
 636
 637        if (unlikely(!timer))
 638                return -EINVAL;
 639
 640        omap_dm_timer_enable(timer);
 641        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 642        l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
 643        if (prescaler >= 0x00 && prescaler <= 0x07) {
 644                l |= OMAP_TIMER_CTRL_PRE;
 645                l |= prescaler << 2;
 646        }
 647        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 648
 649        /* Save the context */
 650        timer->context.tclr = l;
 651        omap_dm_timer_disable(timer);
 652        return 0;
 653}
 654EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
 655
 656int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
 657                                  unsigned int value)
 658{
 659        if (unlikely(!timer))
 660                return -EINVAL;
 661
 662        omap_dm_timer_enable(timer);
 663        __omap_dm_timer_int_enable(timer, value);
 664
 665        /* Save the context */
 666        timer->context.tier = value;
 667        timer->context.twer = value;
 668        omap_dm_timer_disable(timer);
 669        return 0;
 670}
 671EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 672
 673/**
 674 * omap_dm_timer_set_int_disable - disable timer interrupts
 675 * @timer:      pointer to timer handle
 676 * @mask:       bit mask of interrupts to be disabled
 677 *
 678 * Disables the specified timer interrupts for a timer.
 679 */
 680int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
 681{
 682        u32 l = mask;
 683
 684        if (unlikely(!timer))
 685                return -EINVAL;
 686
 687        omap_dm_timer_enable(timer);
 688
 689        if (timer->revision == 1)
 690                l = __raw_readl(timer->irq_ena) & ~mask;
 691
 692        __raw_writel(l, timer->irq_dis);
 693        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
 694        omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
 695
 696        /* Save the context */
 697        timer->context.tier &= ~mask;
 698        timer->context.twer &= ~mask;
 699        omap_dm_timer_disable(timer);
 700        return 0;
 701}
 702EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable);
 703
 704unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 705{
 706        unsigned int l;
 707
 708        if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
 709                pr_err("%s: timer not available or enabled.\n", __func__);
 710                return 0;
 711        }
 712
 713        l = __raw_readl(timer->irq_stat);
 714
 715        return l;
 716}
 717EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
 718
 719int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 720{
 721        if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
 722                return -EINVAL;
 723
 724        __omap_dm_timer_write_status(timer, value);
 725
 726        return 0;
 727}
 728EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
 729
 730unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 731{
 732        if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
 733                pr_err("%s: timer not iavailable or enabled.\n", __func__);
 734                return 0;
 735        }
 736
 737        return __omap_dm_timer_read_counter(timer, timer->posted);
 738}
 739EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 740
 741int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
 742{
 743        if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
 744                pr_err("%s: timer not available or enabled.\n", __func__);
 745                return -EINVAL;
 746        }
 747
 748        omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
 749
 750        /* Save the context */
 751        timer->context.tcrr = value;
 752        return 0;
 753}
 754EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 755
 756int omap_dm_timers_active(void)
 757{
 758        struct omap_dm_timer *timer;
 759
 760        list_for_each_entry(timer, &omap_timer_list, node) {
 761                if (!timer->reserved)
 762                        continue;
 763
 764                if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
 765                    OMAP_TIMER_CTRL_ST) {
 766                        return 1;
 767                }
 768        }
 769        return 0;
 770}
 771EXPORT_SYMBOL_GPL(omap_dm_timers_active);
 772
 773/**
 774 * omap_dm_timer_probe - probe function called for every registered device
 775 * @pdev:       pointer to current timer platform device
 776 *
 777 * Called by driver framework at the end of device registration for all
 778 * timer devices.
 779 */
 780static int omap_dm_timer_probe(struct platform_device *pdev)
 781{
 782        unsigned long flags;
 783        struct omap_dm_timer *timer;
 784        struct resource *mem, *irq;
 785        struct device *dev = &pdev->dev;
 786        struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
 787
 788        if (!pdata && !dev->of_node) {
 789                dev_err(dev, "%s: no platform data.\n", __func__);
 790                return -ENODEV;
 791        }
 792
 793        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 794        if (unlikely(!irq)) {
 795                dev_err(dev, "%s: no IRQ resource.\n", __func__);
 796                return -ENODEV;
 797        }
 798
 799        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 800        if (unlikely(!mem)) {
 801                dev_err(dev, "%s: no memory resource.\n", __func__);
 802                return -ENODEV;
 803        }
 804
 805        timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
 806        if (!timer) {
 807                dev_err(dev, "%s: memory alloc failed!\n", __func__);
 808                return  -ENOMEM;
 809        }
 810
 811        timer->io_base = devm_ioremap_resource(dev, mem);
 812        if (IS_ERR(timer->io_base))
 813                return PTR_ERR(timer->io_base);
 814
 815        if (dev->of_node) {
 816                if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
 817                        timer->capability |= OMAP_TIMER_ALWON;
 818                if (of_find_property(dev->of_node, "ti,timer-dsp", NULL))
 819                        timer->capability |= OMAP_TIMER_HAS_DSP_IRQ;
 820                if (of_find_property(dev->of_node, "ti,timer-pwm", NULL))
 821                        timer->capability |= OMAP_TIMER_HAS_PWM;
 822                if (of_find_property(dev->of_node, "ti,timer-secure", NULL))
 823                        timer->capability |= OMAP_TIMER_SECURE;
 824        } else {
 825                timer->id = pdev->id;
 826                timer->errata = pdata->timer_errata;
 827                timer->capability = pdata->timer_capability;
 828                timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
 829                timer->get_context_loss_count = pdata->get_context_loss_count;
 830        }
 831
 832        timer->irq = irq->start;
 833        timer->pdev = pdev;
 834
 835        /* Skip pm_runtime_enable for OMAP1 */
 836        if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
 837                pm_runtime_enable(dev);
 838                pm_runtime_irq_safe(dev);
 839        }
 840
 841        if (!timer->reserved) {
 842                pm_runtime_get_sync(dev);
 843                __omap_dm_timer_init_regs(timer);
 844                pm_runtime_put(dev);
 845        }
 846
 847        /* add the timer element to the list */
 848        spin_lock_irqsave(&dm_timer_lock, flags);
 849        list_add_tail(&timer->node, &omap_timer_list);
 850        spin_unlock_irqrestore(&dm_timer_lock, flags);
 851
 852        dev_dbg(dev, "Device Probed.\n");
 853
 854        return 0;
 855}
 856
 857/**
 858 * omap_dm_timer_remove - cleanup a registered timer device
 859 * @pdev:       pointer to current timer platform device
 860 *
 861 * Called by driver framework whenever a timer device is unregistered.
 862 * In addition to freeing platform resources it also deletes the timer
 863 * entry from the local list.
 864 */
 865static int omap_dm_timer_remove(struct platform_device *pdev)
 866{
 867        struct omap_dm_timer *timer;
 868        unsigned long flags;
 869        int ret = -EINVAL;
 870
 871        spin_lock_irqsave(&dm_timer_lock, flags);
 872        list_for_each_entry(timer, &omap_timer_list, node)
 873                if (!strcmp(dev_name(&timer->pdev->dev),
 874                            dev_name(&pdev->dev))) {
 875                        list_del(&timer->node);
 876                        ret = 0;
 877                        break;
 878                }
 879        spin_unlock_irqrestore(&dm_timer_lock, flags);
 880
 881        return ret;
 882}
 883
 884static const struct of_device_id omap_timer_match[] = {
 885        { .compatible = "ti,omap2-timer", },
 886        {},
 887};
 888MODULE_DEVICE_TABLE(of, omap_timer_match);
 889
 890static struct platform_driver omap_dm_timer_driver = {
 891        .probe  = omap_dm_timer_probe,
 892        .remove = omap_dm_timer_remove,
 893        .driver = {
 894                .name   = "omap_timer",
 895                .of_match_table = of_match_ptr(omap_timer_match),
 896        },
 897};
 898
 899early_platform_init("earlytimer", &omap_dm_timer_driver);
 900module_platform_driver(omap_dm_timer_driver);
 901
 902MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
 903MODULE_LICENSE("GPL");
 904MODULE_ALIAS("platform:" DRIVER_NAME);
 905MODULE_AUTHOR("Texas Instruments Inc");
 906