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