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