162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/arch/arm/plat-omap/dmtimer.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * OMAP Dual-Mode Timers
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/
862306a36Sopenharmony_ci * Tarun Kanti DebBarma <tarun.kanti@ti.com>
962306a36Sopenharmony_ci * Thara Gopinath <thara@ti.com>
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * dmtimer adaptation to platform_driver.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Copyright (C) 2005 Nokia Corporation
1462306a36Sopenharmony_ci * OMAP2 support by Juha Yrjola
1562306a36Sopenharmony_ci * API improvements and OMAP2 clock framework support by Timo Teras
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * Copyright (C) 2009 Texas Instruments
1862306a36Sopenharmony_ci * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/clk.h>
2262306a36Sopenharmony_ci#include <linux/clk-provider.h>
2362306a36Sopenharmony_ci#include <linux/cpu_pm.h>
2462306a36Sopenharmony_ci#include <linux/module.h>
2562306a36Sopenharmony_ci#include <linux/io.h>
2662306a36Sopenharmony_ci#include <linux/device.h>
2762306a36Sopenharmony_ci#include <linux/err.h>
2862306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2962306a36Sopenharmony_ci#include <linux/of.h>
3062306a36Sopenharmony_ci#include <linux/platform_device.h>
3162306a36Sopenharmony_ci#include <linux/platform_data/dmtimer-omap.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <clocksource/timer-ti-dm.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * timer errata flags
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This
3962306a36Sopenharmony_ci * errata prevents us from using posted mode on these devices, unless the
4062306a36Sopenharmony_ci * timer counter register is never read. For more details please refer to
4162306a36Sopenharmony_ci * the OMAP3/4/5 errata documents.
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_ci#define OMAP_TIMER_ERRATA_I103_I767			0x80000000
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* posted mode types */
4662306a36Sopenharmony_ci#define OMAP_TIMER_NONPOSTED			0x00
4762306a36Sopenharmony_ci#define OMAP_TIMER_POSTED			0x01
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* register offsets with the write pending bit encoded */
5062306a36Sopenharmony_ci#define	WPSHIFT					16
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define OMAP_TIMER_WAKEUP_EN_REG		(_OMAP_TIMER_WAKEUP_EN_OFFSET \
5362306a36Sopenharmony_ci							| (WP_NONE << WPSHIFT))
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define OMAP_TIMER_CTRL_REG			(_OMAP_TIMER_CTRL_OFFSET \
5662306a36Sopenharmony_ci							| (WP_TCLR << WPSHIFT))
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define OMAP_TIMER_COUNTER_REG			(_OMAP_TIMER_COUNTER_OFFSET \
5962306a36Sopenharmony_ci							| (WP_TCRR << WPSHIFT))
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define OMAP_TIMER_LOAD_REG			(_OMAP_TIMER_LOAD_OFFSET \
6262306a36Sopenharmony_ci							| (WP_TLDR << WPSHIFT))
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define OMAP_TIMER_TRIGGER_REG			(_OMAP_TIMER_TRIGGER_OFFSET \
6562306a36Sopenharmony_ci							| (WP_TTGR << WPSHIFT))
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#define OMAP_TIMER_WRITE_PEND_REG		(_OMAP_TIMER_WRITE_PEND_OFFSET \
6862306a36Sopenharmony_ci							| (WP_NONE << WPSHIFT))
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define OMAP_TIMER_MATCH_REG			(_OMAP_TIMER_MATCH_OFFSET \
7162306a36Sopenharmony_ci							| (WP_TMAR << WPSHIFT))
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define OMAP_TIMER_CAPTURE_REG			(_OMAP_TIMER_CAPTURE_OFFSET \
7462306a36Sopenharmony_ci							| (WP_NONE << WPSHIFT))
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define OMAP_TIMER_IF_CTRL_REG			(_OMAP_TIMER_IF_CTRL_OFFSET \
7762306a36Sopenharmony_ci							| (WP_NONE << WPSHIFT))
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define OMAP_TIMER_CAPTURE2_REG			(_OMAP_TIMER_CAPTURE2_OFFSET \
8062306a36Sopenharmony_ci							| (WP_NONE << WPSHIFT))
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define OMAP_TIMER_TICK_POS_REG			(_OMAP_TIMER_TICK_POS_OFFSET \
8362306a36Sopenharmony_ci							| (WP_TPIR << WPSHIFT))
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define OMAP_TIMER_TICK_NEG_REG			(_OMAP_TIMER_TICK_NEG_OFFSET \
8662306a36Sopenharmony_ci							| (WP_TNIR << WPSHIFT))
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define OMAP_TIMER_TICK_COUNT_REG		(_OMAP_TIMER_TICK_COUNT_OFFSET \
8962306a36Sopenharmony_ci							| (WP_TCVR << WPSHIFT))
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define OMAP_TIMER_TICK_INT_MASK_SET_REG				\
9262306a36Sopenharmony_ci		(_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT))
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG				\
9562306a36Sopenharmony_ci		(_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistruct timer_regs {
9862306a36Sopenharmony_ci	u32 ocp_cfg;
9962306a36Sopenharmony_ci	u32 tidr;
10062306a36Sopenharmony_ci	u32 tier;
10162306a36Sopenharmony_ci	u32 twer;
10262306a36Sopenharmony_ci	u32 tclr;
10362306a36Sopenharmony_ci	u32 tcrr;
10462306a36Sopenharmony_ci	u32 tldr;
10562306a36Sopenharmony_ci	u32 ttrg;
10662306a36Sopenharmony_ci	u32 twps;
10762306a36Sopenharmony_ci	u32 tmar;
10862306a36Sopenharmony_ci	u32 tcar1;
10962306a36Sopenharmony_ci	u32 tsicr;
11062306a36Sopenharmony_ci	u32 tcar2;
11162306a36Sopenharmony_ci	u32 tpir;
11262306a36Sopenharmony_ci	u32 tnir;
11362306a36Sopenharmony_ci	u32 tcvr;
11462306a36Sopenharmony_ci	u32 tocr;
11562306a36Sopenharmony_ci	u32 towr;
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistruct dmtimer {
11962306a36Sopenharmony_ci	struct omap_dm_timer cookie;
12062306a36Sopenharmony_ci	int id;
12162306a36Sopenharmony_ci	int irq;
12262306a36Sopenharmony_ci	struct clk *fclk;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	void __iomem	*io_base;
12562306a36Sopenharmony_ci	int		irq_stat;	/* TISR/IRQSTATUS interrupt status */
12662306a36Sopenharmony_ci	int		irq_ena;	/* irq enable */
12762306a36Sopenharmony_ci	int		irq_dis;	/* irq disable, only on v2 ip */
12862306a36Sopenharmony_ci	void __iomem	*pend;		/* write pending */
12962306a36Sopenharmony_ci	void __iomem	*func_base;	/* function register base */
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	atomic_t enabled;
13262306a36Sopenharmony_ci	unsigned long rate;
13362306a36Sopenharmony_ci	unsigned reserved:1;
13462306a36Sopenharmony_ci	unsigned posted:1;
13562306a36Sopenharmony_ci	unsigned omap1:1;
13662306a36Sopenharmony_ci	struct timer_regs context;
13762306a36Sopenharmony_ci	int revision;
13862306a36Sopenharmony_ci	u32 capability;
13962306a36Sopenharmony_ci	u32 errata;
14062306a36Sopenharmony_ci	struct platform_device *pdev;
14162306a36Sopenharmony_ci	struct list_head node;
14262306a36Sopenharmony_ci	struct notifier_block nb;
14362306a36Sopenharmony_ci	struct notifier_block fclk_nb;
14462306a36Sopenharmony_ci	unsigned long fclk_rate;
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic u32 omap_reserved_systimers;
14862306a36Sopenharmony_cistatic LIST_HEAD(omap_timer_list);
14962306a36Sopenharmony_cistatic DEFINE_SPINLOCK(dm_timer_lock);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cienum {
15262306a36Sopenharmony_ci	REQUEST_ANY = 0,
15362306a36Sopenharmony_ci	REQUEST_BY_ID,
15462306a36Sopenharmony_ci	REQUEST_BY_CAP,
15562306a36Sopenharmony_ci	REQUEST_BY_NODE,
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/**
15962306a36Sopenharmony_ci * dmtimer_read - read timer registers in posted and non-posted mode
16062306a36Sopenharmony_ci * @timer:	timer pointer over which read operation to perform
16162306a36Sopenharmony_ci * @reg:	lowest byte holds the register offset
16262306a36Sopenharmony_ci *
16362306a36Sopenharmony_ci * The posted mode bit is encoded in reg. Note that in posted mode, write
16462306a36Sopenharmony_ci * pending bit must be checked. Otherwise a read of a non completed write
16562306a36Sopenharmony_ci * will produce an error.
16662306a36Sopenharmony_ci */
16762306a36Sopenharmony_cistatic inline u32 dmtimer_read(struct dmtimer *timer, u32 reg)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	u16 wp, offset;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	wp = reg >> WPSHIFT;
17262306a36Sopenharmony_ci	offset = reg & 0xff;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/* Wait for a possible write pending bit in posted mode */
17562306a36Sopenharmony_ci	if (wp && timer->posted)
17662306a36Sopenharmony_ci		while (readl_relaxed(timer->pend) & wp)
17762306a36Sopenharmony_ci			cpu_relax();
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	return readl_relaxed(timer->func_base + offset);
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/**
18362306a36Sopenharmony_ci * dmtimer_write - write timer registers in posted and non-posted mode
18462306a36Sopenharmony_ci * @timer:      timer pointer over which write operation is to perform
18562306a36Sopenharmony_ci * @reg:        lowest byte holds the register offset
18662306a36Sopenharmony_ci * @val:        data to write into the register
18762306a36Sopenharmony_ci *
18862306a36Sopenharmony_ci * The posted mode bit is encoded in reg. Note that in posted mode, the write
18962306a36Sopenharmony_ci * pending bit must be checked. Otherwise a write on a register which has a
19062306a36Sopenharmony_ci * pending write will be lost.
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_cistatic inline void dmtimer_write(struct dmtimer *timer, u32 reg, u32 val)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	u16 wp, offset;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	wp = reg >> WPSHIFT;
19762306a36Sopenharmony_ci	offset = reg & 0xff;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* Wait for a possible write pending bit in posted mode */
20062306a36Sopenharmony_ci	if (wp && timer->posted)
20162306a36Sopenharmony_ci		while (readl_relaxed(timer->pend) & wp)
20262306a36Sopenharmony_ci			cpu_relax();
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	writel_relaxed(val, timer->func_base + offset);
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic inline void __omap_dm_timer_init_regs(struct dmtimer *timer)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	u32 tidr;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* Assume v1 ip if bits [31:16] are zero */
21262306a36Sopenharmony_ci	tidr = readl_relaxed(timer->io_base);
21362306a36Sopenharmony_ci	if (!(tidr >> 16)) {
21462306a36Sopenharmony_ci		timer->revision = 1;
21562306a36Sopenharmony_ci		timer->irq_stat = OMAP_TIMER_V1_STAT_OFFSET;
21662306a36Sopenharmony_ci		timer->irq_ena = OMAP_TIMER_V1_INT_EN_OFFSET;
21762306a36Sopenharmony_ci		timer->irq_dis = OMAP_TIMER_V1_INT_EN_OFFSET;
21862306a36Sopenharmony_ci		timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
21962306a36Sopenharmony_ci		timer->func_base = timer->io_base;
22062306a36Sopenharmony_ci	} else {
22162306a36Sopenharmony_ci		timer->revision = 2;
22262306a36Sopenharmony_ci		timer->irq_stat = OMAP_TIMER_V2_IRQSTATUS - OMAP_TIMER_V2_FUNC_OFFSET;
22362306a36Sopenharmony_ci		timer->irq_ena = OMAP_TIMER_V2_IRQENABLE_SET - OMAP_TIMER_V2_FUNC_OFFSET;
22462306a36Sopenharmony_ci		timer->irq_dis = OMAP_TIMER_V2_IRQENABLE_CLR - OMAP_TIMER_V2_FUNC_OFFSET;
22562306a36Sopenharmony_ci		timer->pend = timer->io_base +
22662306a36Sopenharmony_ci			_OMAP_TIMER_WRITE_PEND_OFFSET +
22762306a36Sopenharmony_ci				OMAP_TIMER_V2_FUNC_OFFSET;
22862306a36Sopenharmony_ci		timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci/*
23362306a36Sopenharmony_ci * __omap_dm_timer_enable_posted - enables write posted mode
23462306a36Sopenharmony_ci * @timer:      pointer to timer instance handle
23562306a36Sopenharmony_ci *
23662306a36Sopenharmony_ci * Enables the write posted mode for the timer. When posted mode is enabled
23762306a36Sopenharmony_ci * writes to certain timer registers are immediately acknowledged by the
23862306a36Sopenharmony_ci * internal bus and hence prevents stalling the CPU waiting for the write to
23962306a36Sopenharmony_ci * complete. Enabling this feature can improve performance for writing to the
24062306a36Sopenharmony_ci * timer registers.
24162306a36Sopenharmony_ci */
24262306a36Sopenharmony_cistatic inline void __omap_dm_timer_enable_posted(struct dmtimer *timer)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	if (timer->posted)
24562306a36Sopenharmony_ci		return;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) {
24862306a36Sopenharmony_ci		timer->posted = OMAP_TIMER_NONPOSTED;
24962306a36Sopenharmony_ci		dmtimer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0);
25062306a36Sopenharmony_ci		return;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_IF_CTRL_REG, OMAP_TIMER_CTRL_POSTED);
25462306a36Sopenharmony_ci	timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
25562306a36Sopenharmony_ci	timer->posted = OMAP_TIMER_POSTED;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic inline void __omap_dm_timer_stop(struct dmtimer *timer)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	u32 l;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
26362306a36Sopenharmony_ci	if (l & OMAP_TIMER_CTRL_ST) {
26462306a36Sopenharmony_ci		l &= ~0x1;
26562306a36Sopenharmony_ci		dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);
26662306a36Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP2PLUS
26762306a36Sopenharmony_ci		/* Readback to make sure write has completed */
26862306a36Sopenharmony_ci		dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
26962306a36Sopenharmony_ci		/*
27062306a36Sopenharmony_ci		 * Wait for functional clock period x 3.5 to make sure that
27162306a36Sopenharmony_ci		 * timer is stopped
27262306a36Sopenharmony_ci		 */
27362306a36Sopenharmony_ci		udelay(3500000 / timer->fclk_rate + 1);
27462306a36Sopenharmony_ci#endif
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/* Ack possibly pending interrupt */
27862306a36Sopenharmony_ci	dmtimer_write(timer, timer->irq_stat, OMAP_TIMER_INT_OVERFLOW);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic inline void __omap_dm_timer_int_enable(struct dmtimer *timer,
28262306a36Sopenharmony_ci					      unsigned int value)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	dmtimer_write(timer, timer->irq_ena, value);
28562306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic inline unsigned int
28962306a36Sopenharmony_ci__omap_dm_timer_read_counter(struct dmtimer *timer)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	return dmtimer_read(timer, OMAP_TIMER_COUNTER_REG);
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic inline void __omap_dm_timer_write_status(struct dmtimer *timer,
29562306a36Sopenharmony_ci						unsigned int value)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	dmtimer_write(timer, timer->irq_stat, value);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic void omap_timer_restore_context(struct dmtimer *timer)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, timer->context.ocp_cfg);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, timer->context.twer);
30562306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_COUNTER_REG, timer->context.tcrr);
30662306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_LOAD_REG, timer->context.tldr);
30762306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_MATCH_REG, timer->context.tmar);
30862306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_IF_CTRL_REG, timer->context.tsicr);
30962306a36Sopenharmony_ci	dmtimer_write(timer, timer->irq_ena, timer->context.tier);
31062306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, timer->context.tclr);
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic void omap_timer_save_context(struct dmtimer *timer)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	timer->context.ocp_cfg = dmtimer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	timer->context.tclr = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
31862306a36Sopenharmony_ci	timer->context.twer = dmtimer_read(timer, OMAP_TIMER_WAKEUP_EN_REG);
31962306a36Sopenharmony_ci	timer->context.tldr = dmtimer_read(timer, OMAP_TIMER_LOAD_REG);
32062306a36Sopenharmony_ci	timer->context.tmar = dmtimer_read(timer, OMAP_TIMER_MATCH_REG);
32162306a36Sopenharmony_ci	timer->context.tier = dmtimer_read(timer, timer->irq_ena);
32262306a36Sopenharmony_ci	timer->context.tsicr = dmtimer_read(timer, OMAP_TIMER_IF_CTRL_REG);
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic int omap_timer_context_notifier(struct notifier_block *nb,
32662306a36Sopenharmony_ci				       unsigned long cmd, void *v)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct dmtimer *timer;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	timer = container_of(nb, struct dmtimer, nb);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	switch (cmd) {
33362306a36Sopenharmony_ci	case CPU_CLUSTER_PM_ENTER:
33462306a36Sopenharmony_ci		if ((timer->capability & OMAP_TIMER_ALWON) ||
33562306a36Sopenharmony_ci		    !atomic_read(&timer->enabled))
33662306a36Sopenharmony_ci			break;
33762306a36Sopenharmony_ci		omap_timer_save_context(timer);
33862306a36Sopenharmony_ci		break;
33962306a36Sopenharmony_ci	case CPU_CLUSTER_PM_ENTER_FAILED:	/* No need to restore context */
34062306a36Sopenharmony_ci		break;
34162306a36Sopenharmony_ci	case CPU_CLUSTER_PM_EXIT:
34262306a36Sopenharmony_ci		if ((timer->capability & OMAP_TIMER_ALWON) ||
34362306a36Sopenharmony_ci		    !atomic_read(&timer->enabled))
34462306a36Sopenharmony_ci			break;
34562306a36Sopenharmony_ci		omap_timer_restore_context(timer);
34662306a36Sopenharmony_ci		break;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	return NOTIFY_OK;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic int omap_timer_fclk_notifier(struct notifier_block *nb,
35362306a36Sopenharmony_ci				    unsigned long event, void *data)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct clk_notifier_data *clk_data = data;
35662306a36Sopenharmony_ci	struct dmtimer *timer = container_of(nb, struct dmtimer, fclk_nb);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	switch (event) {
35962306a36Sopenharmony_ci	case POST_RATE_CHANGE:
36062306a36Sopenharmony_ci		timer->fclk_rate = clk_data->new_rate;
36162306a36Sopenharmony_ci		return NOTIFY_OK;
36262306a36Sopenharmony_ci	default:
36362306a36Sopenharmony_ci		return NOTIFY_DONE;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic int omap_dm_timer_reset(struct dmtimer *timer)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	u32 l, timeout = 100000;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (timer->revision != 1)
37262306a36Sopenharmony_ci		return -EINVAL;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	do {
37762306a36Sopenharmony_ci		l = dmtimer_read(timer, OMAP_TIMER_V1_SYS_STAT_OFFSET);
37862306a36Sopenharmony_ci	} while (!l && timeout--);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (!timeout) {
38162306a36Sopenharmony_ci		dev_err(&timer->pdev->dev, "Timer failed to reset\n");
38262306a36Sopenharmony_ci		return -ETIMEDOUT;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* Configure timer for smart-idle mode */
38662306a36Sopenharmony_ci	l = dmtimer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET);
38762306a36Sopenharmony_ci	l |= 0x2 << 0x3;
38862306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, l);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	timer->posted = 0;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	return 0;
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci/*
39662306a36Sopenharmony_ci * Functions exposed to PWM and remoteproc drivers via platform_data.
39762306a36Sopenharmony_ci * Do not use these in the driver, these will get deprecated and will
39862306a36Sopenharmony_ci * will be replaced by Linux generic framework functions such as
39962306a36Sopenharmony_ci * chained interrupts and clock framework.
40062306a36Sopenharmony_ci */
40162306a36Sopenharmony_cistatic struct dmtimer *to_dmtimer(struct omap_dm_timer *cookie)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	if (!cookie)
40462306a36Sopenharmony_ci		return NULL;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return container_of(cookie, struct dmtimer, cookie);
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic int omap_dm_timer_set_source(struct omap_dm_timer *cookie, int source)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	int ret;
41262306a36Sopenharmony_ci	const char *parent_name;
41362306a36Sopenharmony_ci	struct clk *parent;
41462306a36Sopenharmony_ci	struct dmtimer_platform_data *pdata;
41562306a36Sopenharmony_ci	struct dmtimer *timer;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
41862306a36Sopenharmony_ci	if (unlikely(!timer) || IS_ERR(timer->fclk))
41962306a36Sopenharmony_ci		return -EINVAL;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	switch (source) {
42262306a36Sopenharmony_ci	case OMAP_TIMER_SRC_SYS_CLK:
42362306a36Sopenharmony_ci		parent_name = "timer_sys_ck";
42462306a36Sopenharmony_ci		break;
42562306a36Sopenharmony_ci	case OMAP_TIMER_SRC_32_KHZ:
42662306a36Sopenharmony_ci		parent_name = "timer_32k_ck";
42762306a36Sopenharmony_ci		break;
42862306a36Sopenharmony_ci	case OMAP_TIMER_SRC_EXT_CLK:
42962306a36Sopenharmony_ci		parent_name = "timer_ext_ck";
43062306a36Sopenharmony_ci		break;
43162306a36Sopenharmony_ci	default:
43262306a36Sopenharmony_ci		return -EINVAL;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	pdata = timer->pdev->dev.platform_data;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	/*
43862306a36Sopenharmony_ci	 * FIXME: Used for OMAP1 devices only because they do not currently
43962306a36Sopenharmony_ci	 * use the clock framework to set the parent clock. To be removed
44062306a36Sopenharmony_ci	 * once OMAP1 migrated to using clock framework for dmtimers
44162306a36Sopenharmony_ci	 */
44262306a36Sopenharmony_ci	if (timer->omap1 && pdata && pdata->set_timer_src)
44362306a36Sopenharmony_ci		return pdata->set_timer_src(timer->pdev, source);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci#if defined(CONFIG_COMMON_CLK)
44662306a36Sopenharmony_ci	/* Check if the clock has configurable parents */
44762306a36Sopenharmony_ci	if (clk_hw_get_num_parents(__clk_get_hw(timer->fclk)) < 2)
44862306a36Sopenharmony_ci		return 0;
44962306a36Sopenharmony_ci#endif
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	parent = clk_get(&timer->pdev->dev, parent_name);
45262306a36Sopenharmony_ci	if (IS_ERR(parent)) {
45362306a36Sopenharmony_ci		pr_err("%s: %s not found\n", __func__, parent_name);
45462306a36Sopenharmony_ci		return -EINVAL;
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	ret = clk_set_parent(timer->fclk, parent);
45862306a36Sopenharmony_ci	if (ret < 0)
45962306a36Sopenharmony_ci		pr_err("%s: failed to set %s as parent\n", __func__,
46062306a36Sopenharmony_ci			parent_name);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	clk_put(parent);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	return ret;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic void omap_dm_timer_enable(struct omap_dm_timer *cookie)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct dmtimer *timer = to_dmtimer(cookie);
47062306a36Sopenharmony_ci	struct device *dev = &timer->pdev->dev;
47162306a36Sopenharmony_ci	int rc;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	rc = pm_runtime_resume_and_get(dev);
47462306a36Sopenharmony_ci	if (rc)
47562306a36Sopenharmony_ci		dev_err(dev, "could not enable timer\n");
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic void omap_dm_timer_disable(struct omap_dm_timer *cookie)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct dmtimer *timer = to_dmtimer(cookie);
48162306a36Sopenharmony_ci	struct device *dev = &timer->pdev->dev;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic int omap_dm_timer_prepare(struct dmtimer *timer)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct device *dev = &timer->pdev->dev;
48962306a36Sopenharmony_ci	int rc;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	rc = pm_runtime_resume_and_get(dev);
49262306a36Sopenharmony_ci	if (rc)
49362306a36Sopenharmony_ci		return rc;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	if (timer->capability & OMAP_TIMER_NEEDS_RESET) {
49662306a36Sopenharmony_ci		rc = omap_dm_timer_reset(timer);
49762306a36Sopenharmony_ci		if (rc) {
49862306a36Sopenharmony_ci			pm_runtime_put_sync(dev);
49962306a36Sopenharmony_ci			return rc;
50062306a36Sopenharmony_ci		}
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	__omap_dm_timer_enable_posted(timer);
50462306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	return 0;
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic inline u32 omap_dm_timer_reserved_systimer(int id)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0;
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic struct dmtimer *_omap_dm_timer_request(int req_type, void *data)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct dmtimer *timer = NULL, *t;
51762306a36Sopenharmony_ci	struct device_node *np = NULL;
51862306a36Sopenharmony_ci	unsigned long flags;
51962306a36Sopenharmony_ci	u32 cap = 0;
52062306a36Sopenharmony_ci	int id = 0;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	switch (req_type) {
52362306a36Sopenharmony_ci	case REQUEST_BY_ID:
52462306a36Sopenharmony_ci		id = *(int *)data;
52562306a36Sopenharmony_ci		break;
52662306a36Sopenharmony_ci	case REQUEST_BY_CAP:
52762306a36Sopenharmony_ci		cap = *(u32 *)data;
52862306a36Sopenharmony_ci		break;
52962306a36Sopenharmony_ci	case REQUEST_BY_NODE:
53062306a36Sopenharmony_ci		np = (struct device_node *)data;
53162306a36Sopenharmony_ci		break;
53262306a36Sopenharmony_ci	default:
53362306a36Sopenharmony_ci		/* REQUEST_ANY */
53462306a36Sopenharmony_ci		break;
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	spin_lock_irqsave(&dm_timer_lock, flags);
53862306a36Sopenharmony_ci	list_for_each_entry(t, &omap_timer_list, node) {
53962306a36Sopenharmony_ci		if (t->reserved)
54062306a36Sopenharmony_ci			continue;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		switch (req_type) {
54362306a36Sopenharmony_ci		case REQUEST_BY_ID:
54462306a36Sopenharmony_ci			if (id == t->pdev->id) {
54562306a36Sopenharmony_ci				timer = t;
54662306a36Sopenharmony_ci				timer->reserved = 1;
54762306a36Sopenharmony_ci				goto found;
54862306a36Sopenharmony_ci			}
54962306a36Sopenharmony_ci			break;
55062306a36Sopenharmony_ci		case REQUEST_BY_CAP:
55162306a36Sopenharmony_ci			if (cap == (t->capability & cap)) {
55262306a36Sopenharmony_ci				/*
55362306a36Sopenharmony_ci				 * If timer is not NULL, we have already found
55462306a36Sopenharmony_ci				 * one timer. But it was not an exact match
55562306a36Sopenharmony_ci				 * because it had more capabilities than what
55662306a36Sopenharmony_ci				 * was required. Therefore, unreserve the last
55762306a36Sopenharmony_ci				 * timer found and see if this one is a better
55862306a36Sopenharmony_ci				 * match.
55962306a36Sopenharmony_ci				 */
56062306a36Sopenharmony_ci				if (timer)
56162306a36Sopenharmony_ci					timer->reserved = 0;
56262306a36Sopenharmony_ci				timer = t;
56362306a36Sopenharmony_ci				timer->reserved = 1;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci				/* Exit loop early if we find an exact match */
56662306a36Sopenharmony_ci				if (t->capability == cap)
56762306a36Sopenharmony_ci					goto found;
56862306a36Sopenharmony_ci			}
56962306a36Sopenharmony_ci			break;
57062306a36Sopenharmony_ci		case REQUEST_BY_NODE:
57162306a36Sopenharmony_ci			if (np == t->pdev->dev.of_node) {
57262306a36Sopenharmony_ci				timer = t;
57362306a36Sopenharmony_ci				timer->reserved = 1;
57462306a36Sopenharmony_ci				goto found;
57562306a36Sopenharmony_ci			}
57662306a36Sopenharmony_ci			break;
57762306a36Sopenharmony_ci		default:
57862306a36Sopenharmony_ci			/* REQUEST_ANY */
57962306a36Sopenharmony_ci			timer = t;
58062306a36Sopenharmony_ci			timer->reserved = 1;
58162306a36Sopenharmony_ci			goto found;
58262306a36Sopenharmony_ci		}
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_cifound:
58562306a36Sopenharmony_ci	spin_unlock_irqrestore(&dm_timer_lock, flags);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (timer && omap_dm_timer_prepare(timer)) {
58862306a36Sopenharmony_ci		timer->reserved = 0;
58962306a36Sopenharmony_ci		timer = NULL;
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	if (!timer)
59362306a36Sopenharmony_ci		pr_debug("%s: timer request failed!\n", __func__);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	return timer;
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic struct omap_dm_timer *omap_dm_timer_request(void)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	struct dmtimer *timer;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	timer = _omap_dm_timer_request(REQUEST_ANY, NULL);
60362306a36Sopenharmony_ci	if (!timer)
60462306a36Sopenharmony_ci		return NULL;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return &timer->cookie;
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic struct omap_dm_timer *omap_dm_timer_request_specific(int id)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	struct dmtimer *timer;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* Requesting timer by ID is not supported when device tree is used */
61462306a36Sopenharmony_ci	if (of_have_populated_dt()) {
61562306a36Sopenharmony_ci		pr_warn("%s: Please use omap_dm_timer_request_by_node()\n",
61662306a36Sopenharmony_ci			__func__);
61762306a36Sopenharmony_ci		return NULL;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	timer = _omap_dm_timer_request(REQUEST_BY_ID, &id);
62162306a36Sopenharmony_ci	if (!timer)
62262306a36Sopenharmony_ci		return NULL;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	return &timer->cookie;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci/**
62862306a36Sopenharmony_ci * omap_dm_timer_request_by_node - Request a timer by device-tree node
62962306a36Sopenharmony_ci * @np:		Pointer to device-tree timer node
63062306a36Sopenharmony_ci *
63162306a36Sopenharmony_ci * Request a timer based upon a device node pointer. Returns pointer to
63262306a36Sopenharmony_ci * timer handle on success and a NULL pointer on failure.
63362306a36Sopenharmony_ci */
63462306a36Sopenharmony_cistatic struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	struct dmtimer *timer;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	if (!np)
63962306a36Sopenharmony_ci		return NULL;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	timer = _omap_dm_timer_request(REQUEST_BY_NODE, np);
64262306a36Sopenharmony_ci	if (!timer)
64362306a36Sopenharmony_ci		return NULL;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	return &timer->cookie;
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic int omap_dm_timer_free(struct omap_dm_timer *cookie)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	struct dmtimer *timer;
65162306a36Sopenharmony_ci	struct device *dev;
65262306a36Sopenharmony_ci	int rc;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
65562306a36Sopenharmony_ci	if (unlikely(!timer))
65662306a36Sopenharmony_ci		return -EINVAL;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	WARN_ON(!timer->reserved);
65962306a36Sopenharmony_ci	timer->reserved = 0;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	dev = &timer->pdev->dev;
66262306a36Sopenharmony_ci	rc = pm_runtime_resume_and_get(dev);
66362306a36Sopenharmony_ci	if (rc)
66462306a36Sopenharmony_ci		return rc;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	/* Clear timer configuration */
66762306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, 0);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return 0;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic int omap_dm_timer_get_irq(struct omap_dm_timer *cookie)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct dmtimer *timer = to_dmtimer(cookie);
67762306a36Sopenharmony_ci	if (timer)
67862306a36Sopenharmony_ci		return timer->irq;
67962306a36Sopenharmony_ci	return -EINVAL;
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci#if defined(CONFIG_ARCH_OMAP1)
68362306a36Sopenharmony_ci#include <linux/soc/ti/omap1-io.h>
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistatic struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *cookie)
68662306a36Sopenharmony_ci{
68762306a36Sopenharmony_ci	return NULL;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci/**
69162306a36Sopenharmony_ci * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
69262306a36Sopenharmony_ci * @inputmask: current value of idlect mask
69362306a36Sopenharmony_ci */
69462306a36Sopenharmony_ci__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	int i = 0;
69762306a36Sopenharmony_ci	struct dmtimer *timer = NULL;
69862306a36Sopenharmony_ci	unsigned long flags;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	/* If ARMXOR cannot be idled this function call is unnecessary */
70162306a36Sopenharmony_ci	if (!(inputmask & (1 << 1)))
70262306a36Sopenharmony_ci		return inputmask;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	/* If any active timer is using ARMXOR return modified mask */
70562306a36Sopenharmony_ci	spin_lock_irqsave(&dm_timer_lock, flags);
70662306a36Sopenharmony_ci	list_for_each_entry(timer, &omap_timer_list, node) {
70762306a36Sopenharmony_ci		u32 l;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
71062306a36Sopenharmony_ci		if (l & OMAP_TIMER_CTRL_ST) {
71162306a36Sopenharmony_ci			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
71262306a36Sopenharmony_ci				inputmask &= ~(1 << 1);
71362306a36Sopenharmony_ci			else
71462306a36Sopenharmony_ci				inputmask &= ~(1 << 2);
71562306a36Sopenharmony_ci		}
71662306a36Sopenharmony_ci		i++;
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci	spin_unlock_irqrestore(&dm_timer_lock, flags);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	return inputmask;
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci#else
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_cistatic struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *cookie)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	struct dmtimer *timer = to_dmtimer(cookie);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	if (timer && !IS_ERR(timer->fclk))
73062306a36Sopenharmony_ci		return timer->fclk;
73162306a36Sopenharmony_ci	return NULL;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	BUG();
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	return 0;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci#endif
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cistatic int omap_dm_timer_start(struct omap_dm_timer *cookie)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	struct dmtimer *timer;
74662306a36Sopenharmony_ci	struct device *dev;
74762306a36Sopenharmony_ci	int rc;
74862306a36Sopenharmony_ci	u32 l;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
75162306a36Sopenharmony_ci	if (unlikely(!timer))
75262306a36Sopenharmony_ci		return -EINVAL;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	dev = &timer->pdev->dev;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	rc = pm_runtime_resume_and_get(dev);
75762306a36Sopenharmony_ci	if (rc)
75862306a36Sopenharmony_ci		return rc;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
76162306a36Sopenharmony_ci	if (!(l & OMAP_TIMER_CTRL_ST)) {
76262306a36Sopenharmony_ci		l |= OMAP_TIMER_CTRL_ST;
76362306a36Sopenharmony_ci		dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	return 0;
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic int omap_dm_timer_stop(struct omap_dm_timer *cookie)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	struct dmtimer *timer;
77262306a36Sopenharmony_ci	struct device *dev;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
77562306a36Sopenharmony_ci	if (unlikely(!timer))
77662306a36Sopenharmony_ci		return -EINVAL;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	dev = &timer->pdev->dev;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	__omap_dm_timer_stop(timer);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	return 0;
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic int omap_dm_timer_set_load(struct omap_dm_timer *cookie,
78862306a36Sopenharmony_ci				  unsigned int load)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	struct dmtimer *timer;
79162306a36Sopenharmony_ci	struct device *dev;
79262306a36Sopenharmony_ci	int rc;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
79562306a36Sopenharmony_ci	if (unlikely(!timer))
79662306a36Sopenharmony_ci		return -EINVAL;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	dev = &timer->pdev->dev;
79962306a36Sopenharmony_ci	rc = pm_runtime_resume_and_get(dev);
80062306a36Sopenharmony_ci	if (rc)
80162306a36Sopenharmony_ci		return rc;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_LOAD_REG, load);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	return 0;
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_cistatic int omap_dm_timer_set_match(struct omap_dm_timer *cookie, int enable,
81162306a36Sopenharmony_ci				   unsigned int match)
81262306a36Sopenharmony_ci{
81362306a36Sopenharmony_ci	struct dmtimer *timer;
81462306a36Sopenharmony_ci	struct device *dev;
81562306a36Sopenharmony_ci	int rc;
81662306a36Sopenharmony_ci	u32 l;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
81962306a36Sopenharmony_ci	if (unlikely(!timer))
82062306a36Sopenharmony_ci		return -EINVAL;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	dev = &timer->pdev->dev;
82362306a36Sopenharmony_ci	rc = pm_runtime_resume_and_get(dev);
82462306a36Sopenharmony_ci	if (rc)
82562306a36Sopenharmony_ci		return rc;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
82862306a36Sopenharmony_ci	if (enable)
82962306a36Sopenharmony_ci		l |= OMAP_TIMER_CTRL_CE;
83062306a36Sopenharmony_ci	else
83162306a36Sopenharmony_ci		l &= ~OMAP_TIMER_CTRL_CE;
83262306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_MATCH_REG, match);
83362306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	return 0;
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_cistatic int omap_dm_timer_set_pwm(struct omap_dm_timer *cookie, int def_on,
84162306a36Sopenharmony_ci				 int toggle, int trigger, int autoreload)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	struct dmtimer *timer;
84462306a36Sopenharmony_ci	struct device *dev;
84562306a36Sopenharmony_ci	int rc;
84662306a36Sopenharmony_ci	u32 l;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
84962306a36Sopenharmony_ci	if (unlikely(!timer))
85062306a36Sopenharmony_ci		return -EINVAL;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	dev = &timer->pdev->dev;
85362306a36Sopenharmony_ci	rc = pm_runtime_resume_and_get(dev);
85462306a36Sopenharmony_ci	if (rc)
85562306a36Sopenharmony_ci		return rc;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
85862306a36Sopenharmony_ci	l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
85962306a36Sopenharmony_ci	       OMAP_TIMER_CTRL_PT | (0x03 << 10) | OMAP_TIMER_CTRL_AR);
86062306a36Sopenharmony_ci	if (def_on)
86162306a36Sopenharmony_ci		l |= OMAP_TIMER_CTRL_SCPWM;
86262306a36Sopenharmony_ci	if (toggle)
86362306a36Sopenharmony_ci		l |= OMAP_TIMER_CTRL_PT;
86462306a36Sopenharmony_ci	l |= trigger << 10;
86562306a36Sopenharmony_ci	if (autoreload)
86662306a36Sopenharmony_ci		l |= OMAP_TIMER_CTRL_AR;
86762306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	return 0;
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_cistatic int omap_dm_timer_get_pwm_status(struct omap_dm_timer *cookie)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	struct dmtimer *timer;
87762306a36Sopenharmony_ci	struct device *dev;
87862306a36Sopenharmony_ci	int rc;
87962306a36Sopenharmony_ci	u32 l;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
88262306a36Sopenharmony_ci	if (unlikely(!timer))
88362306a36Sopenharmony_ci		return -EINVAL;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	dev = &timer->pdev->dev;
88662306a36Sopenharmony_ci	rc = pm_runtime_resume_and_get(dev);
88762306a36Sopenharmony_ci	if (rc)
88862306a36Sopenharmony_ci		return rc;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	return l;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_cistatic int omap_dm_timer_set_prescaler(struct omap_dm_timer *cookie,
89862306a36Sopenharmony_ci				       int prescaler)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	struct dmtimer *timer;
90162306a36Sopenharmony_ci	struct device *dev;
90262306a36Sopenharmony_ci	int rc;
90362306a36Sopenharmony_ci	u32 l;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
90662306a36Sopenharmony_ci	if (unlikely(!timer) || prescaler < -1 || prescaler > 7)
90762306a36Sopenharmony_ci		return -EINVAL;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	dev = &timer->pdev->dev;
91062306a36Sopenharmony_ci	rc = pm_runtime_resume_and_get(dev);
91162306a36Sopenharmony_ci	if (rc)
91262306a36Sopenharmony_ci		return rc;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
91562306a36Sopenharmony_ci	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
91662306a36Sopenharmony_ci	if (prescaler >= 0) {
91762306a36Sopenharmony_ci		l |= OMAP_TIMER_CTRL_PRE;
91862306a36Sopenharmony_ci		l |= prescaler << 2;
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	return 0;
92562306a36Sopenharmony_ci}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_cistatic int omap_dm_timer_set_int_enable(struct omap_dm_timer *cookie,
92862306a36Sopenharmony_ci					unsigned int value)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	struct dmtimer *timer;
93162306a36Sopenharmony_ci	struct device *dev;
93262306a36Sopenharmony_ci	int rc;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
93562306a36Sopenharmony_ci	if (unlikely(!timer))
93662306a36Sopenharmony_ci		return -EINVAL;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	dev = &timer->pdev->dev;
93962306a36Sopenharmony_ci	rc = pm_runtime_resume_and_get(dev);
94062306a36Sopenharmony_ci	if (rc)
94162306a36Sopenharmony_ci		return rc;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	__omap_dm_timer_int_enable(timer, value);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	return 0;
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci/**
95162306a36Sopenharmony_ci * omap_dm_timer_set_int_disable - disable timer interrupts
95262306a36Sopenharmony_ci * @cookie:	pointer to timer cookie
95362306a36Sopenharmony_ci * @mask:	bit mask of interrupts to be disabled
95462306a36Sopenharmony_ci *
95562306a36Sopenharmony_ci * Disables the specified timer interrupts for a timer.
95662306a36Sopenharmony_ci */
95762306a36Sopenharmony_cistatic int omap_dm_timer_set_int_disable(struct omap_dm_timer *cookie, u32 mask)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	struct dmtimer *timer;
96062306a36Sopenharmony_ci	struct device *dev;
96162306a36Sopenharmony_ci	u32 l = mask;
96262306a36Sopenharmony_ci	int rc;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
96562306a36Sopenharmony_ci	if (unlikely(!timer))
96662306a36Sopenharmony_ci		return -EINVAL;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	dev = &timer->pdev->dev;
96962306a36Sopenharmony_ci	rc = pm_runtime_resume_and_get(dev);
97062306a36Sopenharmony_ci	if (rc)
97162306a36Sopenharmony_ci		return rc;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	if (timer->revision == 1)
97462306a36Sopenharmony_ci		l = dmtimer_read(timer, timer->irq_ena) & ~mask;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	dmtimer_write(timer, timer->irq_dis, l);
97762306a36Sopenharmony_ci	l = dmtimer_read(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
97862306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	return 0;
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_cistatic unsigned int omap_dm_timer_read_status(struct omap_dm_timer *cookie)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	struct dmtimer *timer;
98862306a36Sopenharmony_ci	unsigned int l;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
99162306a36Sopenharmony_ci	if (unlikely(!timer || !atomic_read(&timer->enabled))) {
99262306a36Sopenharmony_ci		pr_err("%s: timer not available or enabled.\n", __func__);
99362306a36Sopenharmony_ci		return 0;
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	l = dmtimer_read(timer, timer->irq_stat);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	return l;
99962306a36Sopenharmony_ci}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cistatic int omap_dm_timer_write_status(struct omap_dm_timer *cookie, unsigned int value)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	struct dmtimer *timer;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
100662306a36Sopenharmony_ci	if (unlikely(!timer || !atomic_read(&timer->enabled)))
100762306a36Sopenharmony_ci		return -EINVAL;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	__omap_dm_timer_write_status(timer, value);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	return 0;
101262306a36Sopenharmony_ci}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_cistatic unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *cookie)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	struct dmtimer *timer;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
101962306a36Sopenharmony_ci	if (unlikely(!timer || !atomic_read(&timer->enabled))) {
102062306a36Sopenharmony_ci		pr_err("%s: timer not iavailable or enabled.\n", __func__);
102162306a36Sopenharmony_ci		return 0;
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	return __omap_dm_timer_read_counter(timer);
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_cistatic int omap_dm_timer_write_counter(struct omap_dm_timer *cookie, unsigned int value)
102862306a36Sopenharmony_ci{
102962306a36Sopenharmony_ci	struct dmtimer *timer;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	timer = to_dmtimer(cookie);
103262306a36Sopenharmony_ci	if (unlikely(!timer || !atomic_read(&timer->enabled))) {
103362306a36Sopenharmony_ci		pr_err("%s: timer not available or enabled.\n", __func__);
103462306a36Sopenharmony_ci		return -EINVAL;
103562306a36Sopenharmony_ci	}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	dmtimer_write(timer, OMAP_TIMER_COUNTER_REG, value);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	/* Save the context */
104062306a36Sopenharmony_ci	timer->context.tcrr = value;
104162306a36Sopenharmony_ci	return 0;
104262306a36Sopenharmony_ci}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_cistatic int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	struct dmtimer *timer = dev_get_drvdata(dev);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	atomic_set(&timer->enabled, 0);
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	if (timer->capability & OMAP_TIMER_ALWON || !timer->func_base)
105162306a36Sopenharmony_ci		return 0;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	omap_timer_save_context(timer);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	return 0;
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_cistatic int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	struct dmtimer *timer = dev_get_drvdata(dev);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	if (!(timer->capability & OMAP_TIMER_ALWON) && timer->func_base)
106362306a36Sopenharmony_ci		omap_timer_restore_context(timer);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	atomic_set(&timer->enabled, 1);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	return 0;
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cistatic const struct dev_pm_ops omap_dm_timer_pm_ops = {
107162306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(omap_dm_timer_runtime_suspend,
107262306a36Sopenharmony_ci			   omap_dm_timer_runtime_resume, NULL)
107362306a36Sopenharmony_ci};
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_cistatic const struct of_device_id omap_timer_match[];
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci/**
107862306a36Sopenharmony_ci * omap_dm_timer_probe - probe function called for every registered device
107962306a36Sopenharmony_ci * @pdev:	pointer to current timer platform device
108062306a36Sopenharmony_ci *
108162306a36Sopenharmony_ci * Called by driver framework at the end of device registration for all
108262306a36Sopenharmony_ci * timer devices.
108362306a36Sopenharmony_ci */
108462306a36Sopenharmony_cistatic int omap_dm_timer_probe(struct platform_device *pdev)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	unsigned long flags;
108762306a36Sopenharmony_ci	struct dmtimer *timer;
108862306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
108962306a36Sopenharmony_ci	const struct dmtimer_platform_data *pdata;
109062306a36Sopenharmony_ci	int ret;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	pdata = of_device_get_match_data(dev);
109362306a36Sopenharmony_ci	if (!pdata)
109462306a36Sopenharmony_ci		pdata = dev_get_platdata(dev);
109562306a36Sopenharmony_ci	else
109662306a36Sopenharmony_ci		dev->platform_data = (void *)pdata;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	if (!pdata) {
109962306a36Sopenharmony_ci		dev_err(dev, "%s: no platform data.\n", __func__);
110062306a36Sopenharmony_ci		return -ENODEV;
110162306a36Sopenharmony_ci	}
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL);
110462306a36Sopenharmony_ci	if (!timer)
110562306a36Sopenharmony_ci		return  -ENOMEM;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	timer->irq = platform_get_irq(pdev, 0);
110862306a36Sopenharmony_ci	if (timer->irq < 0)
110962306a36Sopenharmony_ci		return timer->irq;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	timer->io_base = devm_platform_ioremap_resource(pdev, 0);
111262306a36Sopenharmony_ci	if (IS_ERR(timer->io_base))
111362306a36Sopenharmony_ci		return PTR_ERR(timer->io_base);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	platform_set_drvdata(pdev, timer);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (dev->of_node) {
111862306a36Sopenharmony_ci		if (of_property_read_bool(dev->of_node, "ti,timer-alwon"))
111962306a36Sopenharmony_ci			timer->capability |= OMAP_TIMER_ALWON;
112062306a36Sopenharmony_ci		if (of_property_read_bool(dev->of_node, "ti,timer-dsp"))
112162306a36Sopenharmony_ci			timer->capability |= OMAP_TIMER_HAS_DSP_IRQ;
112262306a36Sopenharmony_ci		if (of_property_read_bool(dev->of_node, "ti,timer-pwm"))
112362306a36Sopenharmony_ci			timer->capability |= OMAP_TIMER_HAS_PWM;
112462306a36Sopenharmony_ci		if (of_property_read_bool(dev->of_node, "ti,timer-secure"))
112562306a36Sopenharmony_ci			timer->capability |= OMAP_TIMER_SECURE;
112662306a36Sopenharmony_ci	} else {
112762306a36Sopenharmony_ci		timer->id = pdev->id;
112862306a36Sopenharmony_ci		timer->capability = pdata->timer_capability;
112962306a36Sopenharmony_ci		timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	timer->omap1 = timer->capability & OMAP_TIMER_NEEDS_RESET;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	/* OMAP1 devices do not yet use the clock framework for dmtimers */
113562306a36Sopenharmony_ci	if (!timer->omap1) {
113662306a36Sopenharmony_ci		timer->fclk = devm_clk_get(dev, "fck");
113762306a36Sopenharmony_ci		if (IS_ERR(timer->fclk))
113862306a36Sopenharmony_ci			return PTR_ERR(timer->fclk);
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci		timer->fclk_nb.notifier_call = omap_timer_fclk_notifier;
114162306a36Sopenharmony_ci		ret = devm_clk_notifier_register(dev, timer->fclk,
114262306a36Sopenharmony_ci						 &timer->fclk_nb);
114362306a36Sopenharmony_ci		if (ret)
114462306a36Sopenharmony_ci			return ret;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci		timer->fclk_rate = clk_get_rate(timer->fclk);
114762306a36Sopenharmony_ci	} else {
114862306a36Sopenharmony_ci		timer->fclk = ERR_PTR(-ENODEV);
114962306a36Sopenharmony_ci	}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	if (!(timer->capability & OMAP_TIMER_ALWON)) {
115262306a36Sopenharmony_ci		timer->nb.notifier_call = omap_timer_context_notifier;
115362306a36Sopenharmony_ci		cpu_pm_register_notifier(&timer->nb);
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	timer->errata = pdata->timer_errata;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	timer->pdev = pdev;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	pm_runtime_enable(dev);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (!timer->reserved) {
116362306a36Sopenharmony_ci		ret = pm_runtime_resume_and_get(dev);
116462306a36Sopenharmony_ci		if (ret) {
116562306a36Sopenharmony_ci			dev_err(dev, "%s: pm_runtime_get_sync failed!\n",
116662306a36Sopenharmony_ci				__func__);
116762306a36Sopenharmony_ci			goto err_disable;
116862306a36Sopenharmony_ci		}
116962306a36Sopenharmony_ci		__omap_dm_timer_init_regs(timer);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci		/* Clear timer configuration */
117262306a36Sopenharmony_ci		dmtimer_write(timer, OMAP_TIMER_CTRL_REG, 0);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci		pm_runtime_put(dev);
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	/* add the timer element to the list */
117862306a36Sopenharmony_ci	spin_lock_irqsave(&dm_timer_lock, flags);
117962306a36Sopenharmony_ci	list_add_tail(&timer->node, &omap_timer_list);
118062306a36Sopenharmony_ci	spin_unlock_irqrestore(&dm_timer_lock, flags);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	dev_dbg(dev, "Device Probed.\n");
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	return 0;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cierr_disable:
118762306a36Sopenharmony_ci	pm_runtime_disable(dev);
118862306a36Sopenharmony_ci	return ret;
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci/**
119262306a36Sopenharmony_ci * omap_dm_timer_remove - cleanup a registered timer device
119362306a36Sopenharmony_ci * @pdev:	pointer to current timer platform device
119462306a36Sopenharmony_ci *
119562306a36Sopenharmony_ci * Called by driver framework whenever a timer device is unregistered.
119662306a36Sopenharmony_ci * In addition to freeing platform resources it also deletes the timer
119762306a36Sopenharmony_ci * entry from the local list.
119862306a36Sopenharmony_ci */
119962306a36Sopenharmony_cistatic void omap_dm_timer_remove(struct platform_device *pdev)
120062306a36Sopenharmony_ci{
120162306a36Sopenharmony_ci	struct dmtimer *timer;
120262306a36Sopenharmony_ci	unsigned long flags;
120362306a36Sopenharmony_ci	int ret = -EINVAL;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	spin_lock_irqsave(&dm_timer_lock, flags);
120662306a36Sopenharmony_ci	list_for_each_entry(timer, &omap_timer_list, node)
120762306a36Sopenharmony_ci		if (!strcmp(dev_name(&timer->pdev->dev),
120862306a36Sopenharmony_ci			    dev_name(&pdev->dev))) {
120962306a36Sopenharmony_ci			if (!(timer->capability & OMAP_TIMER_ALWON))
121062306a36Sopenharmony_ci				cpu_pm_unregister_notifier(&timer->nb);
121162306a36Sopenharmony_ci			list_del(&timer->node);
121262306a36Sopenharmony_ci			ret = 0;
121362306a36Sopenharmony_ci			break;
121462306a36Sopenharmony_ci		}
121562306a36Sopenharmony_ci	spin_unlock_irqrestore(&dm_timer_lock, flags);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	if (ret)
122062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unable to determine timer entry in list of drivers on remove\n");
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic const struct omap_dm_timer_ops dmtimer_ops = {
122462306a36Sopenharmony_ci	.request_by_node = omap_dm_timer_request_by_node,
122562306a36Sopenharmony_ci	.request_specific = omap_dm_timer_request_specific,
122662306a36Sopenharmony_ci	.request = omap_dm_timer_request,
122762306a36Sopenharmony_ci	.set_source = omap_dm_timer_set_source,
122862306a36Sopenharmony_ci	.get_irq = omap_dm_timer_get_irq,
122962306a36Sopenharmony_ci	.set_int_enable = omap_dm_timer_set_int_enable,
123062306a36Sopenharmony_ci	.set_int_disable = omap_dm_timer_set_int_disable,
123162306a36Sopenharmony_ci	.free = omap_dm_timer_free,
123262306a36Sopenharmony_ci	.enable = omap_dm_timer_enable,
123362306a36Sopenharmony_ci	.disable = omap_dm_timer_disable,
123462306a36Sopenharmony_ci	.get_fclk = omap_dm_timer_get_fclk,
123562306a36Sopenharmony_ci	.start = omap_dm_timer_start,
123662306a36Sopenharmony_ci	.stop = omap_dm_timer_stop,
123762306a36Sopenharmony_ci	.set_load = omap_dm_timer_set_load,
123862306a36Sopenharmony_ci	.set_match = omap_dm_timer_set_match,
123962306a36Sopenharmony_ci	.set_pwm = omap_dm_timer_set_pwm,
124062306a36Sopenharmony_ci	.get_pwm_status = omap_dm_timer_get_pwm_status,
124162306a36Sopenharmony_ci	.set_prescaler = omap_dm_timer_set_prescaler,
124262306a36Sopenharmony_ci	.read_counter = omap_dm_timer_read_counter,
124362306a36Sopenharmony_ci	.write_counter = omap_dm_timer_write_counter,
124462306a36Sopenharmony_ci	.read_status = omap_dm_timer_read_status,
124562306a36Sopenharmony_ci	.write_status = omap_dm_timer_write_status,
124662306a36Sopenharmony_ci};
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_cistatic const struct dmtimer_platform_data omap3plus_pdata = {
124962306a36Sopenharmony_ci	.timer_errata = OMAP_TIMER_ERRATA_I103_I767,
125062306a36Sopenharmony_ci	.timer_ops = &dmtimer_ops,
125162306a36Sopenharmony_ci};
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_cistatic const struct dmtimer_platform_data am6_pdata = {
125462306a36Sopenharmony_ci	.timer_ops = &dmtimer_ops,
125562306a36Sopenharmony_ci};
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_cistatic const struct of_device_id omap_timer_match[] = {
125862306a36Sopenharmony_ci	{
125962306a36Sopenharmony_ci		.compatible = "ti,omap2420-timer",
126062306a36Sopenharmony_ci	},
126162306a36Sopenharmony_ci	{
126262306a36Sopenharmony_ci		.compatible = "ti,omap3430-timer",
126362306a36Sopenharmony_ci		.data = &omap3plus_pdata,
126462306a36Sopenharmony_ci	},
126562306a36Sopenharmony_ci	{
126662306a36Sopenharmony_ci		.compatible = "ti,omap4430-timer",
126762306a36Sopenharmony_ci		.data = &omap3plus_pdata,
126862306a36Sopenharmony_ci	},
126962306a36Sopenharmony_ci	{
127062306a36Sopenharmony_ci		.compatible = "ti,omap5430-timer",
127162306a36Sopenharmony_ci		.data = &omap3plus_pdata,
127262306a36Sopenharmony_ci	},
127362306a36Sopenharmony_ci	{
127462306a36Sopenharmony_ci		.compatible = "ti,am335x-timer",
127562306a36Sopenharmony_ci		.data = &omap3plus_pdata,
127662306a36Sopenharmony_ci	},
127762306a36Sopenharmony_ci	{
127862306a36Sopenharmony_ci		.compatible = "ti,am335x-timer-1ms",
127962306a36Sopenharmony_ci		.data = &omap3plus_pdata,
128062306a36Sopenharmony_ci	},
128162306a36Sopenharmony_ci	{
128262306a36Sopenharmony_ci		.compatible = "ti,dm816-timer",
128362306a36Sopenharmony_ci		.data = &omap3plus_pdata,
128462306a36Sopenharmony_ci	},
128562306a36Sopenharmony_ci	{
128662306a36Sopenharmony_ci		.compatible = "ti,am654-timer",
128762306a36Sopenharmony_ci		.data = &am6_pdata,
128862306a36Sopenharmony_ci	},
128962306a36Sopenharmony_ci	{},
129062306a36Sopenharmony_ci};
129162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_timer_match);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_cistatic struct platform_driver omap_dm_timer_driver = {
129462306a36Sopenharmony_ci	.probe  = omap_dm_timer_probe,
129562306a36Sopenharmony_ci	.remove_new = omap_dm_timer_remove,
129662306a36Sopenharmony_ci	.driver = {
129762306a36Sopenharmony_ci		.name   = "omap_timer",
129862306a36Sopenharmony_ci		.of_match_table = omap_timer_match,
129962306a36Sopenharmony_ci		.pm = &omap_dm_timer_pm_ops,
130062306a36Sopenharmony_ci	},
130162306a36Sopenharmony_ci};
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_cimodule_platform_driver(omap_dm_timer_driver);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ciMODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
130662306a36Sopenharmony_ciMODULE_AUTHOR("Texas Instruments Inc");
1307