summaryrefslogtreecommitdiff
path: root/drivers/clocksource
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/arm_arch_timer.c22
-rw-r--r--drivers/clocksource/hyperv_timer.c86
-rw-r--r--drivers/clocksource/ingenic-ost.c10
-rw-r--r--drivers/clocksource/sh_cmt.c88
-rw-r--r--drivers/clocksource/timer-npcm7xx.c10
-rw-r--r--drivers/clocksource/timer-riscv.c2
-rw-r--r--drivers/clocksource/timer-sp804.c6
-rw-r--r--drivers/clocksource/timer-ti-dm-systimer.c4
-rw-r--r--drivers/clocksource/timer-ti-dm.c21
9 files changed, 168 insertions, 81 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index a7ff77550e17..e09d4427f604 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -18,6 +18,7 @@
#include <linux/clocksource.h>
#include <linux/clocksource_ids.h>
#include <linux/interrupt.h>
+#include <linux/kstrtox.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/io.h>
@@ -97,7 +98,7 @@ static bool evtstrm_enable __ro_after_init = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EV
static int __init early_evtstrm_cfg(char *buf)
{
- return strtobool(buf, &evtstrm_enable);
+ return kstrtobool(buf, &evtstrm_enable);
}
early_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg);
@@ -687,8 +688,8 @@ static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id)
return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt);
}
-static __always_inline int timer_shutdown(const int access,
- struct clock_event_device *clk)
+static __always_inline int arch_timer_shutdown(const int access,
+ struct clock_event_device *clk)
{
unsigned long ctrl;
@@ -701,22 +702,22 @@ static __always_inline int timer_shutdown(const int access,
static int arch_timer_shutdown_virt(struct clock_event_device *clk)
{
- return timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk);
+ return arch_timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk);
}
static int arch_timer_shutdown_phys(struct clock_event_device *clk)
{
- return timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk);
+ return arch_timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk);
}
static int arch_timer_shutdown_virt_mem(struct clock_event_device *clk)
{
- return timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk);
+ return arch_timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk);
}
static int arch_timer_shutdown_phys_mem(struct clock_event_device *clk)
{
- return timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk);
+ return arch_timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk);
}
static __always_inline void set_next_event(const int access, unsigned long evt,
@@ -806,6 +807,9 @@ static u64 __arch_timer_check_delta(void)
/*
* XGene-1 implements CVAL in terms of TVAL, meaning
* that the maximum timer range is 32bit. Shame on them.
+ *
+ * Note that TVAL is signed, thus has only 31 of its
+ * 32 bits to express magnitude.
*/
MIDR_ALL_VERSIONS(MIDR_CPU_MODEL(ARM_CPU_IMP_APM,
APM_CPU_PART_POTENZA)),
@@ -813,8 +817,8 @@ static u64 __arch_timer_check_delta(void)
};
if (is_midr_in_range_list(read_cpuid_id(), broken_cval_midrs)) {
- pr_warn_once("Broken CNTx_CVAL_EL1, limiting width to 32bits");
- return CLOCKSOURCE_MASK(32);
+ pr_warn_once("Broken CNTx_CVAL_EL1, using 31 bit TVAL instead.\n");
+ return CLOCKSOURCE_MASK(31);
}
#endif
return CLOCKSOURCE_MASK(arch_counter_get_width());
diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c
index bb47610bbd1c..c0cef92b12b8 100644
--- a/drivers/clocksource/hyperv_timer.c
+++ b/drivers/clocksource/hyperv_timer.c
@@ -21,6 +21,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/acpi.h>
+#include <linux/hyperv.h>
#include <clocksource/hyperv_timer.h>
#include <asm/hyperv-tlfs.h>
#include <asm/mshyperv.h>
@@ -366,9 +367,18 @@ static union {
u8 reserved[PAGE_SIZE];
} tsc_pg __aligned(PAGE_SIZE);
+static struct ms_hyperv_tsc_page *tsc_page = &tsc_pg.page;
+static unsigned long tsc_pfn;
+
+unsigned long hv_get_tsc_pfn(void)
+{
+ return tsc_pfn;
+}
+EXPORT_SYMBOL_GPL(hv_get_tsc_pfn);
+
struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
{
- return &tsc_pg.page;
+ return tsc_page;
}
EXPORT_SYMBOL_GPL(hv_get_tsc_page);
@@ -395,25 +405,24 @@ static u64 notrace read_hv_sched_clock_tsc(void)
static void suspend_hv_clock_tsc(struct clocksource *arg)
{
- u64 tsc_msr;
+ union hv_reference_tsc_msr tsc_msr;
/* Disable the TSC page */
- tsc_msr = hv_get_register(HV_REGISTER_REFERENCE_TSC);
- tsc_msr &= ~BIT_ULL(0);
- hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr);
+ tsc_msr.as_uint64 = hv_get_register(HV_REGISTER_REFERENCE_TSC);
+ tsc_msr.enable = 0;
+ hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr.as_uint64);
}
static void resume_hv_clock_tsc(struct clocksource *arg)
{
- phys_addr_t phys_addr = virt_to_phys(&tsc_pg);
- u64 tsc_msr;
+ union hv_reference_tsc_msr tsc_msr;
/* Re-enable the TSC page */
- tsc_msr = hv_get_register(HV_REGISTER_REFERENCE_TSC);
- tsc_msr &= GENMASK_ULL(11, 0);
- tsc_msr |= BIT_ULL(0) | (u64)phys_addr;
- hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr);
+ tsc_msr.as_uint64 = hv_get_register(HV_REGISTER_REFERENCE_TSC);
+ tsc_msr.enable = 1;
+ tsc_msr.pfn = tsc_pfn;
+ hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr.as_uint64);
}
#ifdef HAVE_VDSO_CLOCKMODE_HVCLOCK
@@ -495,15 +504,11 @@ static __always_inline void hv_setup_sched_clock(void *sched_clock) {}
static bool __init hv_init_tsc_clocksource(void)
{
- u64 tsc_msr;
- phys_addr_t phys_addr;
+ union hv_reference_tsc_msr tsc_msr;
if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE))
return false;
- if (hv_root_partition)
- return false;
-
/*
* If Hyper-V offers TSC_INVARIANT, then the virtualized TSC correctly
* handles frequency and offset changes due to live migration,
@@ -521,19 +526,31 @@ static bool __init hv_init_tsc_clocksource(void)
}
hv_read_reference_counter = read_hv_clock_tsc;
- phys_addr = virt_to_phys(hv_get_tsc_page());
/*
- * The Hyper-V TLFS specifies to preserve the value of reserved
- * bits in registers. So read the existing value, preserve the
- * low order 12 bits, and add in the guest physical address
- * (which already has at least the low 12 bits set to zero since
- * it is page aligned). Also set the "enable" bit, which is bit 0.
+ * TSC page mapping works differently in root compared to guest.
+ * - In guest partition the guest PFN has to be passed to the
+ * hypervisor.
+ * - In root partition it's other way around: it has to map the PFN
+ * provided by the hypervisor.
+ * But it can't be mapped right here as it's too early and MMU isn't
+ * ready yet. So, we only set the enable bit here and will remap the
+ * page later in hv_remap_tsc_clocksource().
+ *
+ * It worth mentioning, that TSC clocksource read function
+ * (read_hv_clock_tsc) has a MSR-based fallback mechanism, used when
+ * TSC page is zeroed (which is the case until the PFN is remapped) and
+ * thus TSC clocksource will work even without the real TSC page
+ * mapped.
*/
- tsc_msr = hv_get_register(HV_REGISTER_REFERENCE_TSC);
- tsc_msr &= GENMASK_ULL(11, 0);
- tsc_msr = tsc_msr | 0x1 | (u64)phys_addr;
- hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr);
+ tsc_msr.as_uint64 = hv_get_register(HV_REGISTER_REFERENCE_TSC);
+ if (hv_root_partition)
+ tsc_pfn = tsc_msr.pfn;
+ else
+ tsc_pfn = HVPFN_DOWN(virt_to_phys(tsc_page));
+ tsc_msr.enable = 1;
+ tsc_msr.pfn = tsc_pfn;
+ hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr.as_uint64);
clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
@@ -565,3 +582,20 @@ void __init hv_init_clocksource(void)
hv_sched_clock_offset = hv_read_reference_counter();
hv_setup_sched_clock(read_hv_sched_clock_msr);
}
+
+void __init hv_remap_tsc_clocksource(void)
+{
+ if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE))
+ return;
+
+ if (!hv_root_partition) {
+ WARN(1, "%s: attempt to remap TSC page in guest partition\n",
+ __func__);
+ return;
+ }
+
+ tsc_page = memremap(tsc_pfn << HV_HYP_PAGE_SHIFT, sizeof(tsc_pg),
+ MEMREMAP_WB);
+ if (!tsc_page)
+ pr_err("Failed to remap Hyper-V TSC page.\n");
+}
diff --git a/drivers/clocksource/ingenic-ost.c b/drivers/clocksource/ingenic-ost.c
index 06d25754e606..9f7c280a1336 100644
--- a/drivers/clocksource/ingenic-ost.c
+++ b/drivers/clocksource/ingenic-ost.c
@@ -141,7 +141,7 @@ static int __init ingenic_ost_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused ingenic_ost_suspend(struct device *dev)
+static int ingenic_ost_suspend(struct device *dev)
{
struct ingenic_ost *ost = dev_get_drvdata(dev);
@@ -150,14 +150,14 @@ static int __maybe_unused ingenic_ost_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ingenic_ost_resume(struct device *dev)
+static int ingenic_ost_resume(struct device *dev)
{
struct ingenic_ost *ost = dev_get_drvdata(dev);
return clk_enable(ost->clk);
}
-static const struct dev_pm_ops __maybe_unused ingenic_ost_pm_ops = {
+static const struct dev_pm_ops ingenic_ost_pm_ops = {
/* _noirq: We want the OST clock to be gated last / ungated first */
.suspend_noirq = ingenic_ost_suspend,
.resume_noirq = ingenic_ost_resume,
@@ -181,9 +181,7 @@ static const struct of_device_id ingenic_ost_of_match[] = {
static struct platform_driver ingenic_ost_driver = {
.driver = {
.name = "ingenic-ost",
-#ifdef CONFIG_PM_SUSPEND
- .pm = &ingenic_ost_pm_ops,
-#endif
+ .pm = pm_sleep_ptr(&ingenic_ost_pm_ops),
.of_match_table = ingenic_ost_of_match,
},
};
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 64dcb082d4cf..7b952aa52c0b 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/module.h>
@@ -116,6 +117,7 @@ struct sh_cmt_device {
void __iomem *mapbase;
struct clk *clk;
unsigned long rate;
+ unsigned int reg_delay;
raw_spinlock_t lock; /* Protect the shared start/stop register */
@@ -247,10 +249,17 @@ static inline u32 sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, u32 value)
{
- if (ch->iostart)
- ch->cmt->info->write_control(ch->iostart, 0, value);
- else
- ch->cmt->info->write_control(ch->cmt->mapbase, 0, value);
+ u32 old_value = sh_cmt_read_cmstr(ch);
+
+ if (value != old_value) {
+ if (ch->iostart) {
+ ch->cmt->info->write_control(ch->iostart, 0, value);
+ udelay(ch->cmt->reg_delay);
+ } else {
+ ch->cmt->info->write_control(ch->cmt->mapbase, 0, value);
+ udelay(ch->cmt->reg_delay);
+ }
+ }
}
static inline u32 sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
@@ -260,7 +269,12 @@ static inline u32 sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, u32 value)
{
- ch->cmt->info->write_control(ch->ioctrl, CMCSR, value);
+ u32 old_value = sh_cmt_read_cmcsr(ch);
+
+ if (value != old_value) {
+ ch->cmt->info->write_control(ch->ioctrl, CMCSR, value);
+ udelay(ch->cmt->reg_delay);
+ }
}
static inline u32 sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
@@ -268,14 +282,33 @@ static inline u32 sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
return ch->cmt->info->read_count(ch->ioctrl, CMCNT);
}
-static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, u32 value)
+static inline int sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, u32 value)
{
+ /* Tests showed that we need to wait 3 clocks here */
+ unsigned int cmcnt_delay = DIV_ROUND_UP(3 * ch->cmt->reg_delay, 2);
+ u32 reg;
+
+ if (ch->cmt->info->model > SH_CMT_16BIT) {
+ int ret = read_poll_timeout_atomic(sh_cmt_read_cmcsr, reg,
+ !(reg & SH_CMT32_CMCSR_WRFLG),
+ 1, cmcnt_delay, false, ch);
+ if (ret < 0)
+ return ret;
+ }
+
ch->cmt->info->write_count(ch->ioctrl, CMCNT, value);
+ udelay(cmcnt_delay);
+ return 0;
}
static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch, u32 value)
{
- ch->cmt->info->write_count(ch->ioctrl, CMCOR, value);
+ u32 old_value = ch->cmt->info->read_count(ch->ioctrl, CMCOR);
+
+ if (value != old_value) {
+ ch->cmt->info->write_count(ch->ioctrl, CMCOR, value);
+ udelay(ch->cmt->reg_delay);
+ }
}
static u32 sh_cmt_get_counter(struct sh_cmt_channel *ch, u32 *has_wrapped)
@@ -319,7 +352,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
static int sh_cmt_enable(struct sh_cmt_channel *ch)
{
- int k, ret;
+ int ret;
dev_pm_syscore_device(&ch->cmt->pdev->dev, true);
@@ -347,26 +380,9 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch)
}
sh_cmt_write_cmcor(ch, 0xffffffff);
- sh_cmt_write_cmcnt(ch, 0);
-
- /*
- * According to the sh73a0 user's manual, as CMCNT can be operated
- * only by the RCLK (Pseudo 32 kHz), there's one restriction on
- * modifying CMCNT register; two RCLK cycles are necessary before
- * this register is either read or any modification of the value
- * it holds is reflected in the LSI's actual operation.
- *
- * While at it, we're supposed to clear out the CMCNT as of this
- * moment, so make sure it's processed properly here. This will
- * take RCLKx2 at maximum.
- */
- for (k = 0; k < 100; k++) {
- if (!sh_cmt_read_cmcnt(ch))
- break;
- udelay(1);
- }
+ ret = sh_cmt_write_cmcnt(ch, 0);
- if (sh_cmt_read_cmcnt(ch)) {
+ if (ret || sh_cmt_read_cmcnt(ch)) {
dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n",
ch->index);
ret = -ETIMEDOUT;
@@ -995,8 +1011,8 @@ MODULE_DEVICE_TABLE(of, sh_cmt_of_table);
static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
{
- unsigned int mask;
- unsigned int i;
+ unsigned int mask, i;
+ unsigned long rate;
int ret;
cmt->pdev = pdev;
@@ -1032,10 +1048,16 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
if (ret < 0)
goto err_clk_unprepare;
- if (cmt->info->width == 16)
- cmt->rate = clk_get_rate(cmt->clk) / 512;
- else
- cmt->rate = clk_get_rate(cmt->clk) / 8;
+ rate = clk_get_rate(cmt->clk);
+ if (!rate) {
+ ret = -EINVAL;
+ goto err_clk_disable;
+ }
+
+ /* We shall wait 2 input clks after register writes */
+ if (cmt->info->model >= SH_CMT_48BIT)
+ cmt->reg_delay = DIV_ROUND_UP(2UL * USEC_PER_SEC, rate);
+ cmt->rate = rate / (cmt->info->width == 16 ? 512 : 8);
/* Map the memory resource(s). */
ret = sh_cmt_map_memory(cmt);
diff --git a/drivers/clocksource/timer-npcm7xx.c b/drivers/clocksource/timer-npcm7xx.c
index a00520cbb660..9af30af5f989 100644
--- a/drivers/clocksource/timer-npcm7xx.c
+++ b/drivers/clocksource/timer-npcm7xx.c
@@ -188,6 +188,7 @@ static void __init npcm7xx_clocksource_init(void)
static int __init npcm7xx_timer_init(struct device_node *np)
{
+ struct clk *clk;
int ret;
ret = timer_of_init(np, &npcm7xx_to);
@@ -199,6 +200,15 @@ static int __init npcm7xx_timer_init(struct device_node *np)
npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate /
(NPCM7XX_Tx_MIN_PRESCALE + 1);
+ /* Enable the clock for timer1, if it exists */
+ clk = of_clk_get(np, 1);
+ if (clk) {
+ if (!IS_ERR(clk))
+ clk_prepare_enable(clk);
+ else
+ pr_warn("%pOF: Failed to get clock for timer1: %pe", np, clk);
+ }
+
npcm7xx_clocksource_init();
npcm7xx_clockevents_init();
diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c
index 969a552da8d2..a0d66fabf073 100644
--- a/drivers/clocksource/timer-riscv.c
+++ b/drivers/clocksource/timer-riscv.c
@@ -51,7 +51,7 @@ static int riscv_clock_next_event(unsigned long delta,
static unsigned int riscv_clock_event_irq;
static DEFINE_PER_CPU(struct clock_event_device, riscv_clock_event) = {
.name = "riscv_timer_clockevent",
- .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 100,
.set_next_event = riscv_clock_next_event,
};
diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c
index e6a87f4af2b5..cd1916c05325 100644
--- a/drivers/clocksource/timer-sp804.c
+++ b/drivers/clocksource/timer-sp804.c
@@ -155,14 +155,14 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static inline void timer_shutdown(struct clock_event_device *evt)
+static inline void evt_timer_shutdown(struct clock_event_device *evt)
{
writel(0, common_clkevt->ctrl);
}
static int sp804_shutdown(struct clock_event_device *evt)
{
- timer_shutdown(evt);
+ evt_timer_shutdown(evt);
return 0;
}
@@ -171,7 +171,7 @@ static int sp804_set_periodic(struct clock_event_device *evt)
unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
- timer_shutdown(evt);
+ evt_timer_shutdown(evt);
writel(common_clkevt->reload, common_clkevt->load);
writel(ctrl, common_clkevt->ctrl);
return 0;
diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c
index 2737407ff069..632523c1232f 100644
--- a/drivers/clocksource/timer-ti-dm-systimer.c
+++ b/drivers/clocksource/timer-ti-dm-systimer.c
@@ -345,8 +345,10 @@ static int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t,
return error;
r = clk_get_rate(clock);
- if (!r)
+ if (!r) {
+ clk_disable_unprepare(clock);
return -ENODEV;
+ }
if (is_ick)
t->ick = clock;
diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
index cad29ded3a48..b24b903a8822 100644
--- a/drivers/clocksource/timer-ti-dm.c
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -633,6 +633,8 @@ static struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *n
static int omap_dm_timer_free(struct omap_dm_timer *cookie)
{
struct dmtimer *timer;
+ struct device *dev;
+ int rc;
timer = to_dmtimer(cookie);
if (unlikely(!timer))
@@ -640,10 +642,21 @@ static int omap_dm_timer_free(struct omap_dm_timer *cookie)
WARN_ON(!timer->reserved);
timer->reserved = 0;
+
+ dev = &timer->pdev->dev;
+ rc = pm_runtime_resume_and_get(dev);
+ if (rc)
+ return rc;
+
+ /* Clear timer configuration */
+ dmtimer_write(timer, OMAP_TIMER_CTRL_REG, 0);
+
+ pm_runtime_put_sync(dev);
+
return 0;
}
-int omap_dm_timer_get_irq(struct omap_dm_timer *cookie)
+static int omap_dm_timer_get_irq(struct omap_dm_timer *cookie)
{
struct dmtimer *timer = to_dmtimer(cookie);
if (timer)
@@ -1135,6 +1148,10 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
goto err_disable;
}
__omap_dm_timer_init_regs(timer);
+
+ /* Clear timer configuration */
+ dmtimer_write(timer, OMAP_TIMER_CTRL_REG, 0);
+
pm_runtime_put(dev);
}
@@ -1258,7 +1275,7 @@ static struct platform_driver omap_dm_timer_driver = {
.remove = omap_dm_timer_remove,
.driver = {
.name = "omap_timer",
- .of_match_table = of_match_ptr(omap_timer_match),
+ .of_match_table = omap_timer_match,
.pm = &omap_dm_timer_pm_ops,
},
};