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 writel_relaxed(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 = readl_relaxed(timer->irq_ena) & ~mask; 703 704 writel_relaxed(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 = readl_relaxed(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 int ret; 803 804 match = of_match_device(of_match_ptr(omap_timer_match), dev); 805 pdata = match ? match->data : dev->platform_data; 806 807 if (!pdata && !dev->of_node) { 808 dev_err(dev, "%s: no platform data.\n", __func__); 809 return -ENODEV; 810 } 811 812 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 813 if (unlikely(!irq)) { 814 dev_err(dev, "%s: no IRQ resource.\n", __func__); 815 return -ENODEV; 816 } 817 818 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 819 if (unlikely(!mem)) { 820 dev_err(dev, "%s: no memory resource.\n", __func__); 821 return -ENODEV; 822 } 823 824 timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL); 825 if (!timer) { 826 dev_err(dev, "%s: memory alloc failed!\n", __func__); 827 return -ENOMEM; 828 } 829 830 timer->fclk = ERR_PTR(-ENODEV); 831 timer->io_base = devm_ioremap_resource(dev, mem); 832 if (IS_ERR(timer->io_base)) 833 return PTR_ERR(timer->io_base); 834 835 if (dev->of_node) { 836 if (of_find_property(dev->of_node, "ti,timer-alwon", NULL)) 837 timer->capability |= OMAP_TIMER_ALWON; 838 if (of_find_property(dev->of_node, "ti,timer-dsp", NULL)) 839 timer->capability |= OMAP_TIMER_HAS_DSP_IRQ; 840 if (of_find_property(dev->of_node, "ti,timer-pwm", NULL)) 841 timer->capability |= OMAP_TIMER_HAS_PWM; 842 if (of_find_property(dev->of_node, "ti,timer-secure", NULL)) 843 timer->capability |= OMAP_TIMER_SECURE; 844 } else { 845 timer->id = pdev->id; 846 timer->capability = pdata->timer_capability; 847 timer->reserved = omap_dm_timer_reserved_systimer(timer->id); 848 timer->get_context_loss_count = pdata->get_context_loss_count; 849 } 850 851 if (pdata) 852 timer->errata = pdata->timer_errata; 853 854 timer->irq = irq->start; 855 timer->pdev = pdev; 856 857 /* Skip pm_runtime_enable for OMAP1 */ 858 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { 859 pm_runtime_enable(dev); 860 pm_runtime_irq_safe(dev); 861 } 862 863 if (!timer->reserved) { 864 ret = pm_runtime_get_sync(dev); 865 if (ret < 0) { 866 dev_err(dev, "%s: pm_runtime_get_sync failed!\n", 867 __func__); 868 goto err_get_sync; 869 } 870 __omap_dm_timer_init_regs(timer); 871 pm_runtime_put(dev); 872 } 873 874 /* add the timer element to the list */ 875 spin_lock_irqsave(&dm_timer_lock, flags); 876 list_add_tail(&timer->node, &omap_timer_list); 877 spin_unlock_irqrestore(&dm_timer_lock, flags); 878 879 dev_dbg(dev, "Device Probed.\n"); 880 881 return 0; 882 883err_get_sync: 884 pm_runtime_put_noidle(dev); 885 pm_runtime_disable(dev); 886 return ret; 887} 888 889/** 890 * omap_dm_timer_remove - cleanup a registered timer device 891 * @pdev: pointer to current timer platform device 892 * 893 * Called by driver framework whenever a timer device is unregistered. 894 * In addition to freeing platform resources it also deletes the timer 895 * entry from the local list. 896 */ 897static int omap_dm_timer_remove(struct platform_device *pdev) 898{ 899 struct omap_dm_timer *timer; 900 unsigned long flags; 901 int ret = -EINVAL; 902 903 spin_lock_irqsave(&dm_timer_lock, flags); 904 list_for_each_entry(timer, &omap_timer_list, node) 905 if (!strcmp(dev_name(&timer->pdev->dev), 906 dev_name(&pdev->dev))) { 907 list_del(&timer->node); 908 ret = 0; 909 break; 910 } 911 spin_unlock_irqrestore(&dm_timer_lock, flags); 912 913 pm_runtime_disable(&pdev->dev); 914 915 return ret; 916} 917 918static const struct dmtimer_platform_data omap3plus_pdata = { 919 .timer_errata = OMAP_TIMER_ERRATA_I103_I767, 920}; 921 922static const struct of_device_id omap_timer_match[] = { 923 { 924 .compatible = "ti,omap2420-timer", 925 }, 926 { 927 .compatible = "ti,omap3430-timer", 928 .data = &omap3plus_pdata, 929 }, 930 { 931 .compatible = "ti,omap4430-timer", 932 .data = &omap3plus_pdata, 933 }, 934 { 935 .compatible = "ti,omap5430-timer", 936 .data = &omap3plus_pdata, 937 }, 938 { 939 .compatible = "ti,am335x-timer", 940 .data = &omap3plus_pdata, 941 }, 942 { 943 .compatible = "ti,am335x-timer-1ms", 944 .data = &omap3plus_pdata, 945 }, 946 {}, 947}; 948MODULE_DEVICE_TABLE(of, omap_timer_match); 949 950static struct platform_driver omap_dm_timer_driver = { 951 .probe = omap_dm_timer_probe, 952 .remove = omap_dm_timer_remove, 953 .driver = { 954 .name = "omap_timer", 955 .of_match_table = of_match_ptr(omap_timer_match), 956 }, 957}; 958 959early_platform_init("earlytimer", &omap_dm_timer_driver); 960module_platform_driver(omap_dm_timer_driver); 961 962MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver"); 963MODULE_LICENSE("GPL"); 964MODULE_ALIAS("platform:" DRIVER_NAME); 965MODULE_AUTHOR("Texas Instruments Inc"); 966