brintos

brintos / linux-shallow public Read only

0
0
Text · 30.5 KiB · b7a34b1 Raw
1306 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * linux/arch/arm/plat-omap/dmtimer.c4 *5 * OMAP Dual-Mode Timers6 *7 * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/8 * Tarun Kanti DebBarma <tarun.kanti@ti.com>9 * Thara Gopinath <thara@ti.com>10 *11 * dmtimer adaptation to platform_driver.12 *13 * Copyright (C) 2005 Nokia Corporation14 * OMAP2 support by Juha Yrjola15 * API improvements and OMAP2 clock framework support by Timo Teras16 *17 * Copyright (C) 2009 Texas Instruments18 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>19 */20 21#include <linux/clk.h>22#include <linux/clk-provider.h>23#include <linux/cpu_pm.h>24#include <linux/module.h>25#include <linux/io.h>26#include <linux/device.h>27#include <linux/err.h>28#include <linux/pm_runtime.h>29#include <linux/of.h>30#include <linux/platform_device.h>31#include <linux/platform_data/dmtimer-omap.h>32 33#include <clocksource/timer-ti-dm.h>34 35/*36 * timer errata flags37 *38 * Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This39 * errata prevents us from using posted mode on these devices, unless the40 * timer counter register is never read. For more details please refer to41 * the OMAP3/4/5 errata documents.42 */43#define OMAP_TIMER_ERRATA_I103_I767			0x8000000044 45/* posted mode types */46#define OMAP_TIMER_NONPOSTED			0x0047#define OMAP_TIMER_POSTED			0x0148 49/* register offsets with the write pending bit encoded */50#define	WPSHIFT					1651 52#define OMAP_TIMER_WAKEUP_EN_REG		(_OMAP_TIMER_WAKEUP_EN_OFFSET \53							| (WP_NONE << WPSHIFT))54 55#define OMAP_TIMER_CTRL_REG			(_OMAP_TIMER_CTRL_OFFSET \56							| (WP_TCLR << WPSHIFT))57 58#define OMAP_TIMER_COUNTER_REG			(_OMAP_TIMER_COUNTER_OFFSET \59							| (WP_TCRR << WPSHIFT))60 61#define OMAP_TIMER_LOAD_REG			(_OMAP_TIMER_LOAD_OFFSET \62							| (WP_TLDR << WPSHIFT))63 64#define OMAP_TIMER_TRIGGER_REG			(_OMAP_TIMER_TRIGGER_OFFSET \65							| (WP_TTGR << WPSHIFT))66 67#define OMAP_TIMER_WRITE_PEND_REG		(_OMAP_TIMER_WRITE_PEND_OFFSET \68							| (WP_NONE << WPSHIFT))69 70#define OMAP_TIMER_MATCH_REG			(_OMAP_TIMER_MATCH_OFFSET \71							| (WP_TMAR << WPSHIFT))72 73#define OMAP_TIMER_CAPTURE_REG			(_OMAP_TIMER_CAPTURE_OFFSET \74							| (WP_NONE << WPSHIFT))75 76#define OMAP_TIMER_IF_CTRL_REG			(_OMAP_TIMER_IF_CTRL_OFFSET \77							| (WP_NONE << WPSHIFT))78 79#define OMAP_TIMER_CAPTURE2_REG			(_OMAP_TIMER_CAPTURE2_OFFSET \80							| (WP_NONE << WPSHIFT))81 82#define OMAP_TIMER_TICK_POS_REG			(_OMAP_TIMER_TICK_POS_OFFSET \83							| (WP_TPIR << WPSHIFT))84 85#define OMAP_TIMER_TICK_NEG_REG			(_OMAP_TIMER_TICK_NEG_OFFSET \86							| (WP_TNIR << WPSHIFT))87 88#define OMAP_TIMER_TICK_COUNT_REG		(_OMAP_TIMER_TICK_COUNT_OFFSET \89							| (WP_TCVR << WPSHIFT))90 91#define OMAP_TIMER_TICK_INT_MASK_SET_REG				\92		(_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT))93 94#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG				\95		(_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))96 97struct timer_regs {98	u32 ocp_cfg;99	u32 tidr;100	u32 tier;101	u32 twer;102	u32 tclr;103	u32 tcrr;104	u32 tldr;105	u32 ttrg;106	u32 twps;107	u32 tmar;108	u32 tcar1;109	u32 tsicr;110	u32 tcar2;111	u32 tpir;112	u32 tnir;113	u32 tcvr;114	u32 tocr;115	u32 towr;116};117 118struct dmtimer {119	struct omap_dm_timer cookie;120	int id;121	int irq;122	struct clk *fclk;123 124	void __iomem	*io_base;125	int		irq_stat;	/* TISR/IRQSTATUS interrupt status */126	int		irq_ena;	/* irq enable */127	int		irq_dis;	/* irq disable, only on v2 ip */128	void __iomem	*pend;		/* write pending */129	void __iomem	*func_base;	/* function register base */130 131	atomic_t enabled;132	unsigned reserved:1;133	unsigned posted:1;134	unsigned omap1:1;135	struct timer_regs context;136	int revision;137	u32 capability;138	u32 errata;139	struct platform_device *pdev;140	struct list_head node;141	struct notifier_block nb;142	struct notifier_block fclk_nb;143	unsigned long fclk_rate;144};145 146static u32 omap_reserved_systimers;147static LIST_HEAD(omap_timer_list);148static DEFINE_SPINLOCK(dm_timer_lock);149 150enum {151	REQUEST_ANY = 0,152	REQUEST_BY_ID,153	REQUEST_BY_CAP,154	REQUEST_BY_NODE,155};156 157/**158 * dmtimer_read - read timer registers in posted and non-posted mode159 * @timer:	timer pointer over which read operation to perform160 * @reg:	lowest byte holds the register offset161 *162 * The posted mode bit is encoded in reg. Note that in posted mode, write163 * pending bit must be checked. Otherwise a read of a non completed write164 * will produce an error.165 */166static inline u32 dmtimer_read(struct dmtimer *timer, u32 reg)167{168	u16 wp, offset;169 170	wp = reg >> WPSHIFT;171	offset = reg & 0xff;172 173	/* Wait for a possible write pending bit in posted mode */174	if (wp && timer->posted)175		while (readl_relaxed(timer->pend) & wp)176			cpu_relax();177 178	return readl_relaxed(timer->func_base + offset);179}180 181/**182 * dmtimer_write - write timer registers in posted and non-posted mode183 * @timer:      timer pointer over which write operation is to perform184 * @reg:        lowest byte holds the register offset185 * @val:        data to write into the register186 *187 * The posted mode bit is encoded in reg. Note that in posted mode, the write188 * pending bit must be checked. Otherwise a write on a register which has a189 * pending write will be lost.190 */191static inline void dmtimer_write(struct dmtimer *timer, u32 reg, u32 val)192{193	u16 wp, offset;194 195	wp = reg >> WPSHIFT;196	offset = reg & 0xff;197 198	/* Wait for a possible write pending bit in posted mode */199	if (wp && timer->posted)200		while (readl_relaxed(timer->pend) & wp)201			cpu_relax();202 203	writel_relaxed(val, timer->func_base + offset);204}205 206static inline void __omap_dm_timer_init_regs(struct dmtimer *timer)207{208	u32 tidr;209 210	/* Assume v1 ip if bits [31:16] are zero */211	tidr = readl_relaxed(timer->io_base);212	if (!(tidr >> 16)) {213		timer->revision = 1;214		timer->irq_stat = OMAP_TIMER_V1_STAT_OFFSET;215		timer->irq_ena = OMAP_TIMER_V1_INT_EN_OFFSET;216		timer->irq_dis = OMAP_TIMER_V1_INT_EN_OFFSET;217		timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;218		timer->func_base = timer->io_base;219	} else {220		timer->revision = 2;221		timer->irq_stat = OMAP_TIMER_V2_IRQSTATUS - OMAP_TIMER_V2_FUNC_OFFSET;222		timer->irq_ena = OMAP_TIMER_V2_IRQENABLE_SET - OMAP_TIMER_V2_FUNC_OFFSET;223		timer->irq_dis = OMAP_TIMER_V2_IRQENABLE_CLR - OMAP_TIMER_V2_FUNC_OFFSET;224		timer->pend = timer->io_base +225			_OMAP_TIMER_WRITE_PEND_OFFSET +226				OMAP_TIMER_V2_FUNC_OFFSET;227		timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;228	}229}230 231/*232 * __omap_dm_timer_enable_posted - enables write posted mode233 * @timer:      pointer to timer instance handle234 *235 * Enables the write posted mode for the timer. When posted mode is enabled236 * writes to certain timer registers are immediately acknowledged by the237 * internal bus and hence prevents stalling the CPU waiting for the write to238 * complete. Enabling this feature can improve performance for writing to the239 * timer registers.240 */241static inline void __omap_dm_timer_enable_posted(struct dmtimer *timer)242{243	if (timer->posted)244		return;245 246	if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) {247		timer->posted = OMAP_TIMER_NONPOSTED;248		dmtimer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0);249		return;250	}251 252	dmtimer_write(timer, OMAP_TIMER_IF_CTRL_REG, OMAP_TIMER_CTRL_POSTED);253	timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;254	timer->posted = OMAP_TIMER_POSTED;255}256 257static inline void __omap_dm_timer_stop(struct dmtimer *timer)258{259	u32 l;260 261	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);262	if (l & OMAP_TIMER_CTRL_ST) {263		l &= ~0x1;264		dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);265#ifdef CONFIG_ARCH_OMAP2PLUS266		/* Readback to make sure write has completed */267		dmtimer_read(timer, OMAP_TIMER_CTRL_REG);268		/*269		 * Wait for functional clock period x 3.5 to make sure that270		 * timer is stopped271		 */272		udelay(3500000 / timer->fclk_rate + 1);273#endif274	}275 276	/* Ack possibly pending interrupt */277	dmtimer_write(timer, timer->irq_stat, OMAP_TIMER_INT_OVERFLOW);278}279 280static inline void __omap_dm_timer_int_enable(struct dmtimer *timer,281					      unsigned int value)282{283	dmtimer_write(timer, timer->irq_ena, value);284	dmtimer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value);285}286 287static inline unsigned int288__omap_dm_timer_read_counter(struct dmtimer *timer)289{290	return dmtimer_read(timer, OMAP_TIMER_COUNTER_REG);291}292 293static inline void __omap_dm_timer_write_status(struct dmtimer *timer,294						unsigned int value)295{296	dmtimer_write(timer, timer->irq_stat, value);297}298 299static void omap_timer_restore_context(struct dmtimer *timer)300{301	dmtimer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, timer->context.ocp_cfg);302 303	dmtimer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, timer->context.twer);304	dmtimer_write(timer, OMAP_TIMER_COUNTER_REG, timer->context.tcrr);305	dmtimer_write(timer, OMAP_TIMER_LOAD_REG, timer->context.tldr);306	dmtimer_write(timer, OMAP_TIMER_MATCH_REG, timer->context.tmar);307	dmtimer_write(timer, OMAP_TIMER_IF_CTRL_REG, timer->context.tsicr);308	dmtimer_write(timer, timer->irq_ena, timer->context.tier);309	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, timer->context.tclr);310}311 312static void omap_timer_save_context(struct dmtimer *timer)313{314	timer->context.ocp_cfg = dmtimer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET);315 316	timer->context.tclr = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);317	timer->context.twer = dmtimer_read(timer, OMAP_TIMER_WAKEUP_EN_REG);318	timer->context.tldr = dmtimer_read(timer, OMAP_TIMER_LOAD_REG);319	timer->context.tmar = dmtimer_read(timer, OMAP_TIMER_MATCH_REG);320	timer->context.tier = dmtimer_read(timer, timer->irq_ena);321	timer->context.tsicr = dmtimer_read(timer, OMAP_TIMER_IF_CTRL_REG);322}323 324static int omap_timer_context_notifier(struct notifier_block *nb,325				       unsigned long cmd, void *v)326{327	struct dmtimer *timer;328 329	timer = container_of(nb, struct dmtimer, nb);330 331	switch (cmd) {332	case CPU_CLUSTER_PM_ENTER:333		if ((timer->capability & OMAP_TIMER_ALWON) ||334		    !atomic_read(&timer->enabled))335			break;336		omap_timer_save_context(timer);337		break;338	case CPU_CLUSTER_PM_ENTER_FAILED:	/* No need to restore context */339		break;340	case CPU_CLUSTER_PM_EXIT:341		if ((timer->capability & OMAP_TIMER_ALWON) ||342		    !atomic_read(&timer->enabled))343			break;344		omap_timer_restore_context(timer);345		break;346	}347 348	return NOTIFY_OK;349}350 351static int omap_timer_fclk_notifier(struct notifier_block *nb,352				    unsigned long event, void *data)353{354	struct clk_notifier_data *clk_data = data;355	struct dmtimer *timer = container_of(nb, struct dmtimer, fclk_nb);356 357	switch (event) {358	case POST_RATE_CHANGE:359		timer->fclk_rate = clk_data->new_rate;360		return NOTIFY_OK;361	default:362		return NOTIFY_DONE;363	}364}365 366static int omap_dm_timer_reset(struct dmtimer *timer)367{368	u32 l, timeout = 100000;369 370	if (timer->revision != 1)371		return -EINVAL;372 373	dmtimer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);374 375	do {376		l = dmtimer_read(timer, OMAP_TIMER_V1_SYS_STAT_OFFSET);377	} while (!l && timeout--);378 379	if (!timeout) {380		dev_err(&timer->pdev->dev, "Timer failed to reset\n");381		return -ETIMEDOUT;382	}383 384	/* Configure timer for smart-idle mode */385	l = dmtimer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET);386	l |= 0x2 << 0x3;387	dmtimer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, l);388 389	timer->posted = 0;390 391	return 0;392}393 394/*395 * Functions exposed to PWM and remoteproc drivers via platform_data.396 * Do not use these in the driver, these will get deprecated and will397 * will be replaced by Linux generic framework functions such as398 * chained interrupts and clock framework.399 */400static struct dmtimer *to_dmtimer(struct omap_dm_timer *cookie)401{402	if (!cookie)403		return NULL;404 405	return container_of(cookie, struct dmtimer, cookie);406}407 408static int omap_dm_timer_set_source(struct omap_dm_timer *cookie, int source)409{410	int ret;411	const char *parent_name;412	struct clk *parent;413	struct dmtimer_platform_data *pdata;414	struct dmtimer *timer;415 416	timer = to_dmtimer(cookie);417	if (unlikely(!timer) || IS_ERR(timer->fclk))418		return -EINVAL;419 420	switch (source) {421	case OMAP_TIMER_SRC_SYS_CLK:422		parent_name = "timer_sys_ck";423		break;424	case OMAP_TIMER_SRC_32_KHZ:425		parent_name = "timer_32k_ck";426		break;427	case OMAP_TIMER_SRC_EXT_CLK:428		parent_name = "timer_ext_ck";429		break;430	default:431		return -EINVAL;432	}433 434	pdata = timer->pdev->dev.platform_data;435 436	/*437	 * FIXME: Used for OMAP1 devices only because they do not currently438	 * use the clock framework to set the parent clock. To be removed439	 * once OMAP1 migrated to using clock framework for dmtimers440	 */441	if (timer->omap1 && pdata && pdata->set_timer_src)442		return pdata->set_timer_src(timer->pdev, source);443 444#if defined(CONFIG_COMMON_CLK)445	/* Check if the clock has configurable parents */446	if (clk_hw_get_num_parents(__clk_get_hw(timer->fclk)) < 2)447		return 0;448#endif449 450	parent = clk_get(&timer->pdev->dev, parent_name);451	if (IS_ERR(parent)) {452		pr_err("%s: %s not found\n", __func__, parent_name);453		return -EINVAL;454	}455 456	ret = clk_set_parent(timer->fclk, parent);457	if (ret < 0)458		pr_err("%s: failed to set %s as parent\n", __func__,459			parent_name);460 461	clk_put(parent);462 463	return ret;464}465 466static void omap_dm_timer_enable(struct omap_dm_timer *cookie)467{468	struct dmtimer *timer = to_dmtimer(cookie);469	struct device *dev = &timer->pdev->dev;470	int rc;471 472	rc = pm_runtime_resume_and_get(dev);473	if (rc)474		dev_err(dev, "could not enable timer\n");475}476 477static void omap_dm_timer_disable(struct omap_dm_timer *cookie)478{479	struct dmtimer *timer = to_dmtimer(cookie);480	struct device *dev = &timer->pdev->dev;481 482	pm_runtime_put_sync(dev);483}484 485static int omap_dm_timer_prepare(struct dmtimer *timer)486{487	struct device *dev = &timer->pdev->dev;488	int rc;489 490	rc = pm_runtime_resume_and_get(dev);491	if (rc)492		return rc;493 494	if (timer->capability & OMAP_TIMER_NEEDS_RESET) {495		rc = omap_dm_timer_reset(timer);496		if (rc) {497			pm_runtime_put_sync(dev);498			return rc;499		}500	}501 502	__omap_dm_timer_enable_posted(timer);503	pm_runtime_put_sync(dev);504 505	return 0;506}507 508static inline u32 omap_dm_timer_reserved_systimer(int id)509{510	return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0;511}512 513static struct dmtimer *_omap_dm_timer_request(int req_type, void *data)514{515	struct dmtimer *timer = NULL, *t;516	struct device_node *np = NULL;517	unsigned long flags;518	u32 cap = 0;519	int id = 0;520 521	switch (req_type) {522	case REQUEST_BY_ID:523		id = *(int *)data;524		break;525	case REQUEST_BY_CAP:526		cap = *(u32 *)data;527		break;528	case REQUEST_BY_NODE:529		np = (struct device_node *)data;530		break;531	default:532		/* REQUEST_ANY */533		break;534	}535 536	spin_lock_irqsave(&dm_timer_lock, flags);537	list_for_each_entry(t, &omap_timer_list, node) {538		if (t->reserved)539			continue;540 541		switch (req_type) {542		case REQUEST_BY_ID:543			if (id == t->pdev->id) {544				timer = t;545				timer->reserved = 1;546				goto found;547			}548			break;549		case REQUEST_BY_CAP:550			if (cap == (t->capability & cap)) {551				/*552				 * If timer is not NULL, we have already found553				 * one timer. But it was not an exact match554				 * because it had more capabilities than what555				 * was required. Therefore, unreserve the last556				 * timer found and see if this one is a better557				 * match.558				 */559				if (timer)560					timer->reserved = 0;561				timer = t;562				timer->reserved = 1;563 564				/* Exit loop early if we find an exact match */565				if (t->capability == cap)566					goto found;567			}568			break;569		case REQUEST_BY_NODE:570			if (np == t->pdev->dev.of_node) {571				timer = t;572				timer->reserved = 1;573				goto found;574			}575			break;576		default:577			/* REQUEST_ANY */578			timer = t;579			timer->reserved = 1;580			goto found;581		}582	}583found:584	spin_unlock_irqrestore(&dm_timer_lock, flags);585 586	if (timer && omap_dm_timer_prepare(timer)) {587		timer->reserved = 0;588		timer = NULL;589	}590 591	if (!timer)592		pr_debug("%s: timer request failed!\n", __func__);593 594	return timer;595}596 597static struct omap_dm_timer *omap_dm_timer_request(void)598{599	struct dmtimer *timer;600 601	timer = _omap_dm_timer_request(REQUEST_ANY, NULL);602	if (!timer)603		return NULL;604 605	return &timer->cookie;606}607 608static struct omap_dm_timer *omap_dm_timer_request_specific(int id)609{610	struct dmtimer *timer;611 612	/* Requesting timer by ID is not supported when device tree is used */613	if (of_have_populated_dt()) {614		pr_warn("%s: Please use omap_dm_timer_request_by_node()\n",615			__func__);616		return NULL;617	}618 619	timer = _omap_dm_timer_request(REQUEST_BY_ID, &id);620	if (!timer)621		return NULL;622 623	return &timer->cookie;624}625 626/**627 * omap_dm_timer_request_by_node - Request a timer by device-tree node628 * @np:		Pointer to device-tree timer node629 *630 * Request a timer based upon a device node pointer. Returns pointer to631 * timer handle on success and a NULL pointer on failure.632 */633static struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np)634{635	struct dmtimer *timer;636 637	if (!np)638		return NULL;639 640	timer = _omap_dm_timer_request(REQUEST_BY_NODE, np);641	if (!timer)642		return NULL;643 644	return &timer->cookie;645}646 647static int omap_dm_timer_free(struct omap_dm_timer *cookie)648{649	struct dmtimer *timer;650	struct device *dev;651	int rc;652 653	timer = to_dmtimer(cookie);654	if (unlikely(!timer))655		return -EINVAL;656 657	WARN_ON(!timer->reserved);658	timer->reserved = 0;659 660	dev = &timer->pdev->dev;661	rc = pm_runtime_resume_and_get(dev);662	if (rc)663		return rc;664 665	/* Clear timer configuration */666	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, 0);667 668	pm_runtime_put_sync(dev);669 670	return 0;671}672 673static int omap_dm_timer_get_irq(struct omap_dm_timer *cookie)674{675	struct dmtimer *timer = to_dmtimer(cookie);676	if (timer)677		return timer->irq;678	return -EINVAL;679}680 681#if defined(CONFIG_ARCH_OMAP1)682#include <linux/soc/ti/omap1-io.h>683 684static struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *cookie)685{686	return NULL;687}688 689/**690 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR691 * @inputmask: current value of idlect mask692 */693__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)694{695	int i = 0;696	struct dmtimer *timer = NULL;697	unsigned long flags;698 699	/* If ARMXOR cannot be idled this function call is unnecessary */700	if (!(inputmask & (1 << 1)))701		return inputmask;702 703	/* If any active timer is using ARMXOR return modified mask */704	spin_lock_irqsave(&dm_timer_lock, flags);705	list_for_each_entry(timer, &omap_timer_list, node) {706		u32 l;707 708		l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);709		if (l & OMAP_TIMER_CTRL_ST) {710			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)711				inputmask &= ~(1 << 1);712			else713				inputmask &= ~(1 << 2);714		}715		i++;716	}717	spin_unlock_irqrestore(&dm_timer_lock, flags);718 719	return inputmask;720}721 722#else723 724static struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *cookie)725{726	struct dmtimer *timer = to_dmtimer(cookie);727 728	if (timer && !IS_ERR(timer->fclk))729		return timer->fclk;730	return NULL;731}732 733__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)734{735	BUG();736 737	return 0;738}739 740#endif741 742static int omap_dm_timer_start(struct omap_dm_timer *cookie)743{744	struct dmtimer *timer;745	struct device *dev;746	int rc;747	u32 l;748 749	timer = to_dmtimer(cookie);750	if (unlikely(!timer))751		return -EINVAL;752 753	dev = &timer->pdev->dev;754 755	rc = pm_runtime_resume_and_get(dev);756	if (rc)757		return rc;758 759	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);760	if (!(l & OMAP_TIMER_CTRL_ST)) {761		l |= OMAP_TIMER_CTRL_ST;762		dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);763	}764 765	return 0;766}767 768static int omap_dm_timer_stop(struct omap_dm_timer *cookie)769{770	struct dmtimer *timer;771	struct device *dev;772 773	timer = to_dmtimer(cookie);774	if (unlikely(!timer))775		return -EINVAL;776 777	dev = &timer->pdev->dev;778 779	__omap_dm_timer_stop(timer);780 781	pm_runtime_put_sync(dev);782 783	return 0;784}785 786static int omap_dm_timer_set_load(struct omap_dm_timer *cookie,787				  unsigned int load)788{789	struct dmtimer *timer;790	struct device *dev;791	int rc;792 793	timer = to_dmtimer(cookie);794	if (unlikely(!timer))795		return -EINVAL;796 797	dev = &timer->pdev->dev;798	rc = pm_runtime_resume_and_get(dev);799	if (rc)800		return rc;801 802	dmtimer_write(timer, OMAP_TIMER_LOAD_REG, load);803 804	pm_runtime_put_sync(dev);805 806	return 0;807}808 809static int omap_dm_timer_set_match(struct omap_dm_timer *cookie, int enable,810				   unsigned int match)811{812	struct dmtimer *timer;813	struct device *dev;814	int rc;815	u32 l;816 817	timer = to_dmtimer(cookie);818	if (unlikely(!timer))819		return -EINVAL;820 821	dev = &timer->pdev->dev;822	rc = pm_runtime_resume_and_get(dev);823	if (rc)824		return rc;825 826	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);827	if (enable)828		l |= OMAP_TIMER_CTRL_CE;829	else830		l &= ~OMAP_TIMER_CTRL_CE;831	dmtimer_write(timer, OMAP_TIMER_MATCH_REG, match);832	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);833 834	pm_runtime_put_sync(dev);835 836	return 0;837}838 839static int omap_dm_timer_set_pwm(struct omap_dm_timer *cookie, int def_on,840				 int toggle, int trigger, int autoreload)841{842	struct dmtimer *timer;843	struct device *dev;844	int rc;845	u32 l;846 847	timer = to_dmtimer(cookie);848	if (unlikely(!timer))849		return -EINVAL;850 851	dev = &timer->pdev->dev;852	rc = pm_runtime_resume_and_get(dev);853	if (rc)854		return rc;855 856	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);857	l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |858	       OMAP_TIMER_CTRL_PT | (0x03 << 10) | OMAP_TIMER_CTRL_AR);859	if (def_on)860		l |= OMAP_TIMER_CTRL_SCPWM;861	if (toggle)862		l |= OMAP_TIMER_CTRL_PT;863	l |= trigger << 10;864	if (autoreload)865		l |= OMAP_TIMER_CTRL_AR;866	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);867 868	pm_runtime_put_sync(dev);869 870	return 0;871}872 873static int omap_dm_timer_get_pwm_status(struct omap_dm_timer *cookie)874{875	struct dmtimer *timer;876	struct device *dev;877	int rc;878	u32 l;879 880	timer = to_dmtimer(cookie);881	if (unlikely(!timer))882		return -EINVAL;883 884	dev = &timer->pdev->dev;885	rc = pm_runtime_resume_and_get(dev);886	if (rc)887		return rc;888 889	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);890 891	pm_runtime_put_sync(dev);892 893	return l;894}895 896static int omap_dm_timer_set_prescaler(struct omap_dm_timer *cookie,897				       int prescaler)898{899	struct dmtimer *timer;900	struct device *dev;901	int rc;902	u32 l;903 904	timer = to_dmtimer(cookie);905	if (unlikely(!timer) || prescaler < -1 || prescaler > 7)906		return -EINVAL;907 908	dev = &timer->pdev->dev;909	rc = pm_runtime_resume_and_get(dev);910	if (rc)911		return rc;912 913	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);914	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));915	if (prescaler >= 0) {916		l |= OMAP_TIMER_CTRL_PRE;917		l |= prescaler << 2;918	}919	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);920 921	pm_runtime_put_sync(dev);922 923	return 0;924}925 926static int omap_dm_timer_set_int_enable(struct omap_dm_timer *cookie,927					unsigned int value)928{929	struct dmtimer *timer;930	struct device *dev;931	int rc;932 933	timer = to_dmtimer(cookie);934	if (unlikely(!timer))935		return -EINVAL;936 937	dev = &timer->pdev->dev;938	rc = pm_runtime_resume_and_get(dev);939	if (rc)940		return rc;941 942	__omap_dm_timer_int_enable(timer, value);943 944	pm_runtime_put_sync(dev);945 946	return 0;947}948 949/**950 * omap_dm_timer_set_int_disable - disable timer interrupts951 * @cookie:	pointer to timer cookie952 * @mask:	bit mask of interrupts to be disabled953 *954 * Disables the specified timer interrupts for a timer.955 */956static int omap_dm_timer_set_int_disable(struct omap_dm_timer *cookie, u32 mask)957{958	struct dmtimer *timer;959	struct device *dev;960	u32 l = mask;961	int rc;962 963	timer = to_dmtimer(cookie);964	if (unlikely(!timer))965		return -EINVAL;966 967	dev = &timer->pdev->dev;968	rc = pm_runtime_resume_and_get(dev);969	if (rc)970		return rc;971 972	if (timer->revision == 1)973		l = dmtimer_read(timer, timer->irq_ena) & ~mask;974 975	dmtimer_write(timer, timer->irq_dis, l);976	l = dmtimer_read(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;977	dmtimer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, l);978 979	pm_runtime_put_sync(dev);980 981	return 0;982}983 984static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *cookie)985{986	struct dmtimer *timer;987	unsigned int l;988 989	timer = to_dmtimer(cookie);990	if (unlikely(!timer || !atomic_read(&timer->enabled))) {991		pr_err("%s: timer not available or enabled.\n", __func__);992		return 0;993	}994 995	l = dmtimer_read(timer, timer->irq_stat);996 997	return l;998}999 1000static int omap_dm_timer_write_status(struct omap_dm_timer *cookie, unsigned int value)1001{1002	struct dmtimer *timer;1003 1004	timer = to_dmtimer(cookie);1005	if (unlikely(!timer || !atomic_read(&timer->enabled)))1006		return -EINVAL;1007 1008	__omap_dm_timer_write_status(timer, value);1009 1010	return 0;1011}1012 1013static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *cookie)1014{1015	struct dmtimer *timer;1016 1017	timer = to_dmtimer(cookie);1018	if (unlikely(!timer || !atomic_read(&timer->enabled))) {1019		pr_err("%s: timer not iavailable or enabled.\n", __func__);1020		return 0;1021	}1022 1023	return __omap_dm_timer_read_counter(timer);1024}1025 1026static int omap_dm_timer_write_counter(struct omap_dm_timer *cookie, unsigned int value)1027{1028	struct dmtimer *timer;1029 1030	timer = to_dmtimer(cookie);1031	if (unlikely(!timer || !atomic_read(&timer->enabled))) {1032		pr_err("%s: timer not available or enabled.\n", __func__);1033		return -EINVAL;1034	}1035 1036	dmtimer_write(timer, OMAP_TIMER_COUNTER_REG, value);1037 1038	/* Save the context */1039	timer->context.tcrr = value;1040	return 0;1041}1042 1043static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev)1044{1045	struct dmtimer *timer = dev_get_drvdata(dev);1046 1047	atomic_set(&timer->enabled, 0);1048 1049	if (timer->capability & OMAP_TIMER_ALWON || !timer->func_base)1050		return 0;1051 1052	omap_timer_save_context(timer);1053 1054	return 0;1055}1056 1057static int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev)1058{1059	struct dmtimer *timer = dev_get_drvdata(dev);1060 1061	if (!(timer->capability & OMAP_TIMER_ALWON) && timer->func_base)1062		omap_timer_restore_context(timer);1063 1064	atomic_set(&timer->enabled, 1);1065 1066	return 0;1067}1068 1069static const struct dev_pm_ops omap_dm_timer_pm_ops = {1070	SET_RUNTIME_PM_OPS(omap_dm_timer_runtime_suspend,1071			   omap_dm_timer_runtime_resume, NULL)1072};1073 1074static const struct of_device_id omap_timer_match[];1075 1076/**1077 * omap_dm_timer_probe - probe function called for every registered device1078 * @pdev:	pointer to current timer platform device1079 *1080 * Called by driver framework at the end of device registration for all1081 * timer devices.1082 */1083static int omap_dm_timer_probe(struct platform_device *pdev)1084{1085	unsigned long flags;1086	struct dmtimer *timer;1087	struct device *dev = &pdev->dev;1088	const struct dmtimer_platform_data *pdata;1089	int ret;1090 1091	pdata = of_device_get_match_data(dev);1092	if (!pdata)1093		pdata = dev_get_platdata(dev);1094	else1095		dev->platform_data = (void *)pdata;1096 1097	if (!pdata) {1098		dev_err(dev, "%s: no platform data.\n", __func__);1099		return -ENODEV;1100	}1101 1102	timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL);1103	if (!timer)1104		return  -ENOMEM;1105 1106	timer->irq = platform_get_irq(pdev, 0);1107	if (timer->irq < 0)1108		return timer->irq;1109 1110	timer->io_base = devm_platform_ioremap_resource(pdev, 0);1111	if (IS_ERR(timer->io_base))1112		return PTR_ERR(timer->io_base);1113 1114	platform_set_drvdata(pdev, timer);1115 1116	if (dev->of_node) {1117		if (of_property_read_bool(dev->of_node, "ti,timer-alwon"))1118			timer->capability |= OMAP_TIMER_ALWON;1119		if (of_property_read_bool(dev->of_node, "ti,timer-dsp"))1120			timer->capability |= OMAP_TIMER_HAS_DSP_IRQ;1121		if (of_property_read_bool(dev->of_node, "ti,timer-pwm"))1122			timer->capability |= OMAP_TIMER_HAS_PWM;1123		if (of_property_read_bool(dev->of_node, "ti,timer-secure"))1124			timer->capability |= OMAP_TIMER_SECURE;1125	} else {1126		timer->id = pdev->id;1127		timer->capability = pdata->timer_capability;1128		timer->reserved = omap_dm_timer_reserved_systimer(timer->id);1129	}1130 1131	timer->omap1 = timer->capability & OMAP_TIMER_NEEDS_RESET;1132 1133	/* OMAP1 devices do not yet use the clock framework for dmtimers */1134	if (!timer->omap1) {1135		timer->fclk = devm_clk_get(dev, "fck");1136		if (IS_ERR(timer->fclk))1137			return PTR_ERR(timer->fclk);1138 1139		timer->fclk_nb.notifier_call = omap_timer_fclk_notifier;1140		ret = devm_clk_notifier_register(dev, timer->fclk,1141						 &timer->fclk_nb);1142		if (ret)1143			return ret;1144 1145		timer->fclk_rate = clk_get_rate(timer->fclk);1146	} else {1147		timer->fclk = ERR_PTR(-ENODEV);1148	}1149 1150	if (!(timer->capability & OMAP_TIMER_ALWON)) {1151		timer->nb.notifier_call = omap_timer_context_notifier;1152		cpu_pm_register_notifier(&timer->nb);1153	}1154 1155	timer->errata = pdata->timer_errata;1156 1157	timer->pdev = pdev;1158 1159	pm_runtime_enable(dev);1160 1161	if (!timer->reserved) {1162		ret = pm_runtime_resume_and_get(dev);1163		if (ret) {1164			dev_err(dev, "%s: pm_runtime_get_sync failed!\n",1165				__func__);1166			goto err_disable;1167		}1168		__omap_dm_timer_init_regs(timer);1169 1170		/* Clear timer configuration */1171		dmtimer_write(timer, OMAP_TIMER_CTRL_REG, 0);1172 1173		pm_runtime_put(dev);1174	}1175 1176	/* add the timer element to the list */1177	spin_lock_irqsave(&dm_timer_lock, flags);1178	list_add_tail(&timer->node, &omap_timer_list);1179	spin_unlock_irqrestore(&dm_timer_lock, flags);1180 1181	dev_dbg(dev, "Device Probed.\n");1182 1183	return 0;1184 1185err_disable:1186	pm_runtime_disable(dev);1187	return ret;1188}1189 1190/**1191 * omap_dm_timer_remove - cleanup a registered timer device1192 * @pdev:	pointer to current timer platform device1193 *1194 * Called by driver framework whenever a timer device is unregistered.1195 * In addition to freeing platform resources it also deletes the timer1196 * entry from the local list.1197 */1198static void omap_dm_timer_remove(struct platform_device *pdev)1199{1200	struct dmtimer *timer;1201	unsigned long flags;1202	int ret = -EINVAL;1203 1204	spin_lock_irqsave(&dm_timer_lock, flags);1205	list_for_each_entry(timer, &omap_timer_list, node)1206		if (!strcmp(dev_name(&timer->pdev->dev),1207			    dev_name(&pdev->dev))) {1208			if (!(timer->capability & OMAP_TIMER_ALWON))1209				cpu_pm_unregister_notifier(&timer->nb);1210			list_del(&timer->node);1211			ret = 0;1212			break;1213		}1214	spin_unlock_irqrestore(&dm_timer_lock, flags);1215 1216	pm_runtime_disable(&pdev->dev);1217 1218	if (ret)1219		dev_err(&pdev->dev, "Unable to determine timer entry in list of drivers on remove\n");1220}1221 1222static const struct omap_dm_timer_ops dmtimer_ops = {1223	.request_by_node = omap_dm_timer_request_by_node,1224	.request_specific = omap_dm_timer_request_specific,1225	.request = omap_dm_timer_request,1226	.set_source = omap_dm_timer_set_source,1227	.get_irq = omap_dm_timer_get_irq,1228	.set_int_enable = omap_dm_timer_set_int_enable,1229	.set_int_disable = omap_dm_timer_set_int_disable,1230	.free = omap_dm_timer_free,1231	.enable = omap_dm_timer_enable,1232	.disable = omap_dm_timer_disable,1233	.get_fclk = omap_dm_timer_get_fclk,1234	.start = omap_dm_timer_start,1235	.stop = omap_dm_timer_stop,1236	.set_load = omap_dm_timer_set_load,1237	.set_match = omap_dm_timer_set_match,1238	.set_pwm = omap_dm_timer_set_pwm,1239	.get_pwm_status = omap_dm_timer_get_pwm_status,1240	.set_prescaler = omap_dm_timer_set_prescaler,1241	.read_counter = omap_dm_timer_read_counter,1242	.write_counter = omap_dm_timer_write_counter,1243	.read_status = omap_dm_timer_read_status,1244	.write_status = omap_dm_timer_write_status,1245};1246 1247static const struct dmtimer_platform_data omap3plus_pdata = {1248	.timer_errata = OMAP_TIMER_ERRATA_I103_I767,1249	.timer_ops = &dmtimer_ops,1250};1251 1252static const struct dmtimer_platform_data am6_pdata = {1253	.timer_ops = &dmtimer_ops,1254};1255 1256static const struct of_device_id omap_timer_match[] = {1257	{1258		.compatible = "ti,omap2420-timer",1259	},1260	{1261		.compatible = "ti,omap3430-timer",1262		.data = &omap3plus_pdata,1263	},1264	{1265		.compatible = "ti,omap4430-timer",1266		.data = &omap3plus_pdata,1267	},1268	{1269		.compatible = "ti,omap5430-timer",1270		.data = &omap3plus_pdata,1271	},1272	{1273		.compatible = "ti,am335x-timer",1274		.data = &omap3plus_pdata,1275	},1276	{1277		.compatible = "ti,am335x-timer-1ms",1278		.data = &omap3plus_pdata,1279	},1280	{1281		.compatible = "ti,dm816-timer",1282		.data = &omap3plus_pdata,1283	},1284	{1285		.compatible = "ti,am654-timer",1286		.data = &am6_pdata,1287	},1288	{},1289};1290MODULE_DEVICE_TABLE(of, omap_timer_match);1291 1292static struct platform_driver omap_dm_timer_driver = {1293	.probe  = omap_dm_timer_probe,1294	.remove_new = omap_dm_timer_remove,1295	.driver = {1296		.name   = "omap_timer",1297		.of_match_table = omap_timer_match,1298		.pm = &omap_dm_timer_pm_ops,1299	},1300};1301 1302module_platform_driver(omap_dm_timer_driver);1303 1304MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");1305MODULE_AUTHOR("Texas Instruments Inc");1306