mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	 7da390694a
			
		
	
	
		7da390694a
		
	
	
	
	
		
			
			When DEBUG is defined this error occurs
drivers/clocksource/mxs_timer.c:138:1: error:
  expected ‘;’ before ‘}’ token
The preceding statement needs a semicolon.
Replace pr_info() with pr_debug() and remove the unneeded ifdef.
Fixes: eb8703e2ef ("clockevents/drivers/mxs: Migrate to new 'set-state' interface")
Signed-off-by: Tom Rix <trix@redhat.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20210118211955.763609-1-trix@redhat.com
		
	
			
		
			
				
	
	
		
			273 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			273 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| //
 | |
| //  Copyright (C) 2000-2001 Deep Blue Solutions
 | |
| //  Copyright (C) 2002 Shane Nay (shane@minirl.com)
 | |
| //  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
 | |
| //  Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
 | |
| //  Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
 | |
| 
 | |
| #include <linux/err.h>
 | |
| #include <linux/interrupt.h>
 | |
| #include <linux/irq.h>
 | |
| #include <linux/clockchips.h>
 | |
| #include <linux/clk.h>
 | |
| #include <linux/of.h>
 | |
| #include <linux/of_address.h>
 | |
| #include <linux/of_irq.h>
 | |
| #include <linux/stmp_device.h>
 | |
| #include <linux/sched_clock.h>
 | |
| 
 | |
| /*
 | |
|  * There are 2 versions of the timrot on Freescale MXS-based SoCs.
 | |
|  * The v1 on MX23 only gets 16 bits counter, while v2 on MX28
 | |
|  * extends the counter to 32 bits.
 | |
|  *
 | |
|  * The implementation uses two timers, one for clock_event and
 | |
|  * another for clocksource. MX28 uses timrot 0 and 1, while MX23
 | |
|  * uses 0 and 2.
 | |
|  */
 | |
| 
 | |
| #define MX23_TIMROT_VERSION_OFFSET	0x0a0
 | |
| #define MX28_TIMROT_VERSION_OFFSET	0x120
 | |
| #define BP_TIMROT_MAJOR_VERSION		24
 | |
| #define BV_TIMROT_VERSION_1		0x01
 | |
| #define BV_TIMROT_VERSION_2		0x02
 | |
| #define timrot_is_v1()	(timrot_major_version == BV_TIMROT_VERSION_1)
 | |
| 
 | |
| /*
 | |
|  * There are 4 registers for each timrotv2 instance, and 2 registers
 | |
|  * for each timrotv1. So address step 0x40 in macros below strides
 | |
|  * one instance of timrotv2 while two instances of timrotv1.
 | |
|  *
 | |
|  * As the result, HW_TIMROT_XXXn(1) defines the address of timrot1
 | |
|  * on MX28 while timrot2 on MX23.
 | |
|  */
 | |
| /* common between v1 and v2 */
 | |
| #define HW_TIMROT_ROTCTRL		0x00
 | |
| #define HW_TIMROT_TIMCTRLn(n)		(0x20 + (n) * 0x40)
 | |
| /* v1 only */
 | |
| #define HW_TIMROT_TIMCOUNTn(n)		(0x30 + (n) * 0x40)
 | |
| /* v2 only */
 | |
| #define HW_TIMROT_RUNNING_COUNTn(n)	(0x30 + (n) * 0x40)
 | |
| #define HW_TIMROT_FIXED_COUNTn(n)	(0x40 + (n) * 0x40)
 | |
| 
 | |
| #define BM_TIMROT_TIMCTRLn_RELOAD	(1 << 6)
 | |
| #define BM_TIMROT_TIMCTRLn_UPDATE	(1 << 7)
 | |
| #define BM_TIMROT_TIMCTRLn_IRQ_EN	(1 << 14)
 | |
| #define BM_TIMROT_TIMCTRLn_IRQ		(1 << 15)
 | |
| #define BP_TIMROT_TIMCTRLn_SELECT	0
 | |
| #define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL		0x8
 | |
| #define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL		0xb
 | |
| #define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS	0xf
 | |
| 
 | |
| static struct clock_event_device mxs_clockevent_device;
 | |
| 
 | |
| static void __iomem *mxs_timrot_base;
 | |
| static u32 timrot_major_version;
 | |
| 
 | |
| static inline void timrot_irq_disable(void)
 | |
| {
 | |
| 	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
 | |
| 		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
 | |
| }
 | |
| 
 | |
| static inline void timrot_irq_enable(void)
 | |
| {
 | |
| 	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
 | |
| 		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_SET);
 | |
| }
 | |
| 
 | |
| static void timrot_irq_acknowledge(void)
 | |
| {
 | |
| 	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ, mxs_timrot_base +
 | |
| 		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
 | |
| }
 | |
| 
 | |
| static u64 timrotv1_get_cycles(struct clocksource *cs)
 | |
| {
 | |
| 	return ~((__raw_readl(mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1))
 | |
| 			& 0xffff0000) >> 16);
 | |
| }
 | |
| 
 | |
| static int timrotv1_set_next_event(unsigned long evt,
 | |
| 					struct clock_event_device *dev)
 | |
| {
 | |
| 	/* timrot decrements the count */
 | |
| 	__raw_writel(evt, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(0));
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int timrotv2_set_next_event(unsigned long evt,
 | |
| 					struct clock_event_device *dev)
 | |
| {
 | |
| 	/* timrot decrements the count */
 | |
| 	__raw_writel(evt, mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(0));
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static irqreturn_t mxs_timer_interrupt(int irq, void *dev_id)
 | |
| {
 | |
| 	struct clock_event_device *evt = dev_id;
 | |
| 
 | |
| 	timrot_irq_acknowledge();
 | |
| 	evt->event_handler(evt);
 | |
| 
 | |
| 	return IRQ_HANDLED;
 | |
| }
 | |
| 
 | |
| static void mxs_irq_clear(char *state)
 | |
| {
 | |
| 	/* Disable interrupt in timer module */
 | |
| 	timrot_irq_disable();
 | |
| 
 | |
| 	/* Set event time into the furthest future */
 | |
| 	if (timrot_is_v1())
 | |
| 		__raw_writel(0xffff, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
 | |
| 	else
 | |
| 		__raw_writel(0xffffffff,
 | |
| 			     mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
 | |
| 
 | |
| 	/* Clear pending interrupt */
 | |
| 	timrot_irq_acknowledge();
 | |
| 	pr_debug("%s: changing mode to %s\n", __func__, state);
 | |
| }
 | |
| 
 | |
| static int mxs_shutdown(struct clock_event_device *evt)
 | |
| {
 | |
| 	mxs_irq_clear("shutdown");
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int mxs_set_oneshot(struct clock_event_device *evt)
 | |
| {
 | |
| 	if (clockevent_state_oneshot(evt))
 | |
| 		mxs_irq_clear("oneshot");
 | |
| 	timrot_irq_enable();
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static struct clock_event_device mxs_clockevent_device = {
 | |
| 	.name			= "mxs_timrot",
 | |
| 	.features		= CLOCK_EVT_FEAT_ONESHOT,
 | |
| 	.set_state_shutdown	= mxs_shutdown,
 | |
| 	.set_state_oneshot	= mxs_set_oneshot,
 | |
| 	.tick_resume		= mxs_shutdown,
 | |
| 	.set_next_event		= timrotv2_set_next_event,
 | |
| 	.rating			= 200,
 | |
| };
 | |
| 
 | |
| static int __init mxs_clockevent_init(struct clk *timer_clk)
 | |
| {
 | |
| 	if (timrot_is_v1())
 | |
| 		mxs_clockevent_device.set_next_event = timrotv1_set_next_event;
 | |
| 	mxs_clockevent_device.cpumask = cpumask_of(0);
 | |
| 	clockevents_config_and_register(&mxs_clockevent_device,
 | |
| 					clk_get_rate(timer_clk),
 | |
| 					timrot_is_v1() ? 0xf : 0x2,
 | |
| 					timrot_is_v1() ? 0xfffe : 0xfffffffe);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static struct clocksource clocksource_mxs = {
 | |
| 	.name		= "mxs_timer",
 | |
| 	.rating		= 200,
 | |
| 	.read		= timrotv1_get_cycles,
 | |
| 	.mask		= CLOCKSOURCE_MASK(16),
 | |
| 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 | |
| };
 | |
| 
 | |
| static u64 notrace mxs_read_sched_clock_v2(void)
 | |
| {
 | |
| 	return ~readl_relaxed(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1));
 | |
| }
 | |
| 
 | |
| static int __init mxs_clocksource_init(struct clk *timer_clk)
 | |
| {
 | |
| 	unsigned int c = clk_get_rate(timer_clk);
 | |
| 
 | |
| 	if (timrot_is_v1())
 | |
| 		clocksource_register_hz(&clocksource_mxs, c);
 | |
| 	else {
 | |
| 		clocksource_mmio_init(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1),
 | |
| 			"mxs_timer", c, 200, 32, clocksource_mmio_readl_down);
 | |
| 		sched_clock_register(mxs_read_sched_clock_v2, 32, c);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int __init mxs_timer_init(struct device_node *np)
 | |
| {
 | |
| 	struct clk *timer_clk;
 | |
| 	int irq, ret;
 | |
| 
 | |
| 	mxs_timrot_base = of_iomap(np, 0);
 | |
| 	WARN_ON(!mxs_timrot_base);
 | |
| 
 | |
| 	timer_clk = of_clk_get(np, 0);
 | |
| 	if (IS_ERR(timer_clk)) {
 | |
| 		pr_err("%s: failed to get clk\n", __func__);
 | |
| 		return PTR_ERR(timer_clk);
 | |
| 	}
 | |
| 
 | |
| 	ret = clk_prepare_enable(timer_clk);
 | |
| 	if (ret)
 | |
| 		return ret;
 | |
| 
 | |
| 	/*
 | |
| 	 * Initialize timers to a known state
 | |
| 	 */
 | |
| 	stmp_reset_block(mxs_timrot_base + HW_TIMROT_ROTCTRL);
 | |
| 
 | |
| 	/* get timrot version */
 | |
| 	timrot_major_version = __raw_readl(mxs_timrot_base +
 | |
| 			(of_device_is_compatible(np, "fsl,imx23-timrot") ?
 | |
| 						MX23_TIMROT_VERSION_OFFSET :
 | |
| 						MX28_TIMROT_VERSION_OFFSET));
 | |
| 	timrot_major_version >>= BP_TIMROT_MAJOR_VERSION;
 | |
| 
 | |
| 	/* one for clock_event */
 | |
| 	__raw_writel((timrot_is_v1() ?
 | |
| 			BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
 | |
| 			BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
 | |
| 			BM_TIMROT_TIMCTRLn_UPDATE |
 | |
| 			BM_TIMROT_TIMCTRLn_IRQ_EN,
 | |
| 			mxs_timrot_base + HW_TIMROT_TIMCTRLn(0));
 | |
| 
 | |
| 	/* another for clocksource */
 | |
| 	__raw_writel((timrot_is_v1() ?
 | |
| 			BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
 | |
| 			BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
 | |
| 			BM_TIMROT_TIMCTRLn_RELOAD,
 | |
| 			mxs_timrot_base + HW_TIMROT_TIMCTRLn(1));
 | |
| 
 | |
| 	/* set clocksource timer fixed count to the maximum */
 | |
| 	if (timrot_is_v1())
 | |
| 		__raw_writel(0xffff,
 | |
| 			mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
 | |
| 	else
 | |
| 		__raw_writel(0xffffffff,
 | |
| 			mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
 | |
| 
 | |
| 	/* init and register the timer to the framework */
 | |
| 	ret = mxs_clocksource_init(timer_clk);
 | |
| 	if (ret)
 | |
| 		return ret;
 | |
| 
 | |
| 	ret = mxs_clockevent_init(timer_clk);
 | |
| 	if (ret)
 | |
| 		return ret;
 | |
| 
 | |
| 	/* Make irqs happen */
 | |
| 	irq = irq_of_parse_and_map(np, 0);
 | |
| 	if (irq <= 0)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	return request_irq(irq, mxs_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
 | |
| 			   "MXS Timer Tick", &mxs_clockevent_device);
 | |
| }
 | |
| TIMER_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init);
 |