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