Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
   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");