diff options
Diffstat (limited to 'drivers/clocksource')
| -rw-r--r-- | drivers/clocksource/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/clocksource/Makefile | 3 | ||||
| -rw-r--r-- | drivers/clocksource/bcm2835_timer.c | 12 | ||||
| -rw-r--r-- | drivers/clocksource/clksrc-of.c | 5 | ||||
| -rw-r--r-- | drivers/clocksource/mxs_timer.c | 304 | ||||
| -rw-r--r-- | drivers/clocksource/sun4i_timer.c (renamed from drivers/clocksource/sunxi_timer.c) | 94 | ||||
| -rw-r--r-- | drivers/clocksource/tegra20_timer.c | 75 | ||||
| -rw-r--r-- | drivers/clocksource/vt8500_timer.c | 16 | 
8 files changed, 382 insertions, 129 deletions
| diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index e507ab7df60..9002185a0a1 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -25,7 +25,7 @@ config DW_APB_TIMER_OF  config ARMADA_370_XP_TIMER  	bool -config SUNXI_TIMER +config SUN4I_TIMER  	bool  config VT8500_TIMER diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 96e25319659..4897f243a00 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -16,7 +16,8 @@ obj-$(CONFIG_CLKSRC_NOMADIK_MTU)	+= nomadik-mtu.o  obj-$(CONFIG_CLKSRC_DBX500_PRCMU)	+= clksrc-dbx500-prcmu.o  obj-$(CONFIG_ARMADA_370_XP_TIMER)	+= time-armada-370-xp.o  obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o -obj-$(CONFIG_SUNXI_TIMER)	+= sunxi_timer.o +obj-$(CONFIG_ARCH_MXS)		+= mxs_timer.o +obj-$(CONFIG_SUN4I_TIMER)	+= sun4i_timer.o  obj-$(CONFIG_ARCH_TEGRA)	+= tegra20_timer.o  obj-$(CONFIG_VT8500_TIMER)	+= vt8500_timer.o  obj-$(CONFIG_ARCH_BCM)		+= bcm_kona_timer.o diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 50c68fef944..766611d2994 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -95,23 +95,13 @@ static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id)  	}  } -static struct of_device_id bcm2835_time_match[] __initconst = { -	{ .compatible = "brcm,bcm2835-system-timer" }, -	{} -}; - -static void __init bcm2835_timer_init(void) +static void __init bcm2835_timer_init(struct device_node *node)  { -	struct device_node *node;  	void __iomem *base;  	u32 freq;  	int irq;  	struct bcm2835_timer *timer; -	node = of_find_matching_node(NULL, bcm2835_time_match); -	if (!node) -		panic("No bcm2835 timer node"); -  	base = of_iomap(node, 0);  	if (!base)  		panic("Can't remap registers"); diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c index bdabdaa8d00..37f5325bec9 100644 --- a/drivers/clocksource/clksrc-of.c +++ b/drivers/clocksource/clksrc-of.c @@ -16,6 +16,7 @@  #include <linux/init.h>  #include <linux/of.h> +#include <linux/clocksource.h>  extern struct of_device_id __clksrc_of_table[]; @@ -26,10 +27,10 @@ void __init clocksource_of_init(void)  {  	struct device_node *np;  	const struct of_device_id *match; -	void (*init_func)(void); +	clocksource_of_init_fn init_func;  	for_each_matching_node_and_match(np, __clksrc_of_table, &match) {  		init_func = match->data; -		init_func(); +		init_func(np);  	}  } diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c new file mode 100644 index 00000000000..02af4204af8 --- /dev/null +++ b/drivers/clocksource/mxs_timer.c @@ -0,0 +1,304 @@ +/* + *  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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#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 <asm/mach/time.h> +#include <asm/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 enum clock_event_mode mxs_clockevent_mode = CLOCK_EVT_MODE_UNUSED; + +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 cycle_t 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 struct irqaction mxs_timer_irq = { +	.name		= "MXS Timer Tick", +	.dev_id		= &mxs_clockevent_device, +	.flags		= IRQF_TIMER | IRQF_IRQPOLL, +	.handler	= mxs_timer_interrupt, +}; + +#ifdef DEBUG +static const char *clock_event_mode_label[] const = { +	[CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC", +	[CLOCK_EVT_MODE_ONESHOT]  = "CLOCK_EVT_MODE_ONESHOT", +	[CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN", +	[CLOCK_EVT_MODE_UNUSED]   = "CLOCK_EVT_MODE_UNUSED" +}; +#endif /* DEBUG */ + +static void mxs_set_mode(enum clock_event_mode mode, +				struct clock_event_device *evt) +{ +	/* Disable interrupt in timer module */ +	timrot_irq_disable(); + +	if (mode != mxs_clockevent_mode) { +		/* 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(); +	} + +#ifdef DEBUG +	pr_info("%s: changing mode from %s to %s\n", __func__, +		clock_event_mode_label[mxs_clockevent_mode], +		clock_event_mode_label[mode]); +#endif /* DEBUG */ + +	/* Remember timer mode */ +	mxs_clockevent_mode = mode; + +	switch (mode) { +	case CLOCK_EVT_MODE_PERIODIC: +		pr_err("%s: Periodic mode is not implemented\n", __func__); +		break; +	case CLOCK_EVT_MODE_ONESHOT: +		timrot_irq_enable(); +		break; +	case CLOCK_EVT_MODE_SHUTDOWN: +	case CLOCK_EVT_MODE_UNUSED: +	case CLOCK_EVT_MODE_RESUME: +		/* Left event sources disabled, no more interrupts appear */ +		break; +	} +} + +static struct clock_event_device mxs_clockevent_device = { +	.name		= "mxs_timrot", +	.features	= CLOCK_EVT_FEAT_ONESHOT, +	.set_mode	= mxs_set_mode, +	.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 u32 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); +		setup_sched_clock(mxs_read_sched_clock_v2, 32, c); +	} + +	return 0; +} + +static void __init mxs_timer_init(struct device_node *np) +{ +	struct clk *timer_clk; +	int irq; + +	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; +	} + +	clk_prepare_enable(timer_clk); + +	/* +	 * 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 */ +	mxs_clocksource_init(timer_clk); +	mxs_clockevent_init(timer_clk); + +	/* Make irqs happen */ +	irq = irq_of_parse_and_map(np, 0); +	setup_irq(irq, &mxs_timer_irq); +} +CLOCKSOURCE_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init); diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sun4i_timer.c index 0ce85e29769..d4674e78ef3 100644 --- a/drivers/clocksource/sunxi_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -22,66 +22,64 @@  #include <linux/of.h>  #include <linux/of_address.h>  #include <linux/of_irq.h> -#include <linux/sunxi_timer.h> -#include <linux/clk/sunxi.h> -#define TIMER_CTL_REG		0x00 -#define TIMER_CTL_ENABLE		(1 << 0) +#define TIMER_IRQ_EN_REG	0x00 +#define TIMER_IRQ_EN(val)		(1 << val)  #define TIMER_IRQ_ST_REG	0x04 -#define TIMER0_CTL_REG		0x10 -#define TIMER0_CTL_ENABLE		(1 << 0) -#define TIMER0_CTL_AUTORELOAD		(1 << 1) -#define TIMER0_CTL_ONESHOT		(1 << 7) -#define TIMER0_INTVAL_REG	0x14 -#define TIMER0_CNTVAL_REG	0x18 +#define TIMER_CTL_REG(val)	(0x10 * val + 0x10) +#define TIMER_CTL_ENABLE		(1 << 0) +#define TIMER_CTL_AUTORELOAD		(1 << 1) +#define TIMER_CTL_ONESHOT		(1 << 7) +#define TIMER_INTVAL_REG(val)	(0x10 * val + 0x14) +#define TIMER_CNTVAL_REG(val)	(0x10 * val + 0x18)  #define TIMER_SCAL		16  static void __iomem *timer_base; -static void sunxi_clkevt_mode(enum clock_event_mode mode, +static void sun4i_clkevt_mode(enum clock_event_mode mode,  			      struct clock_event_device *clk)  { -	u32 u = readl(timer_base + TIMER0_CTL_REG); +	u32 u = readl(timer_base + TIMER_CTL_REG(0));  	switch (mode) {  	case CLOCK_EVT_MODE_PERIODIC: -		u &= ~(TIMER0_CTL_ONESHOT); -		writel(u | TIMER0_CTL_ENABLE, timer_base + TIMER0_CTL_REG); +		u &= ~(TIMER_CTL_ONESHOT); +		writel(u | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0));  		break;  	case CLOCK_EVT_MODE_ONESHOT: -		writel(u | TIMER0_CTL_ONESHOT, timer_base + TIMER0_CTL_REG); +		writel(u | TIMER_CTL_ONESHOT, timer_base + TIMER_CTL_REG(0));  		break;  	case CLOCK_EVT_MODE_UNUSED:  	case CLOCK_EVT_MODE_SHUTDOWN:  	default: -		writel(u & ~(TIMER0_CTL_ENABLE), timer_base + TIMER0_CTL_REG); +		writel(u & ~(TIMER_CTL_ENABLE), timer_base + TIMER_CTL_REG(0));  		break;  	}  } -static int sunxi_clkevt_next_event(unsigned long evt, +static int sun4i_clkevt_next_event(unsigned long evt,  				   struct clock_event_device *unused)  { -	u32 u = readl(timer_base + TIMER0_CTL_REG); -	writel(evt, timer_base + TIMER0_CNTVAL_REG); -	writel(u | TIMER0_CTL_ENABLE | TIMER0_CTL_AUTORELOAD, -	       timer_base + TIMER0_CTL_REG); +	u32 u = readl(timer_base + TIMER_CTL_REG(0)); +	writel(evt, timer_base + TIMER_CNTVAL_REG(0)); +	writel(u | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD, +	       timer_base + TIMER_CTL_REG(0));  	return 0;  } -static struct clock_event_device sunxi_clockevent = { -	.name = "sunxi_tick", +static struct clock_event_device sun4i_clockevent = { +	.name = "sun4i_tick",  	.rating = 300,  	.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, -	.set_mode = sunxi_clkevt_mode, -	.set_next_event = sunxi_clkevt_next_event, +	.set_mode = sun4i_clkevt_mode, +	.set_next_event = sun4i_clkevt_next_event,  }; -static irqreturn_t sunxi_timer_interrupt(int irq, void *dev_id) +static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id)  {  	struct clock_event_device *evt = (struct clock_event_device *)dev_id; @@ -91,30 +89,20 @@ static irqreturn_t sunxi_timer_interrupt(int irq, void *dev_id)  	return IRQ_HANDLED;  } -static struct irqaction sunxi_timer_irq = { -	.name = "sunxi_timer0", +static struct irqaction sun4i_timer_irq = { +	.name = "sun4i_timer0",  	.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, -	.handler = sunxi_timer_interrupt, -	.dev_id = &sunxi_clockevent, -}; - -static struct of_device_id sunxi_timer_dt_ids[] = { -	{ .compatible = "allwinner,sunxi-timer" }, -	{ } +	.handler = sun4i_timer_interrupt, +	.dev_id = &sun4i_clockevent,  }; -void __init sunxi_timer_init(void) +static void __init sun4i_timer_init(struct device_node *node)  { -	struct device_node *node;  	unsigned long rate = 0;  	struct clk *clk;  	int ret, irq;  	u32 val; -	node = of_find_matching_node(NULL, sunxi_timer_dt_ids); -	if (!node) -		panic("No sunxi timer node"); -  	timer_base = of_iomap(node, 0);  	if (!timer_base)  		panic("Can't map registers"); @@ -123,8 +111,6 @@ void __init sunxi_timer_init(void)  	if (irq <= 0)  		panic("Can't parse IRQ"); -	sunxi_init_clocks(); -  	clk = of_clk_get(node, 0);  	if (IS_ERR(clk))  		panic("Can't get timer clock"); @@ -132,29 +118,31 @@ void __init sunxi_timer_init(void)  	rate = clk_get_rate(clk);  	writel(rate / (TIMER_SCAL * HZ), -	       timer_base + TIMER0_INTVAL_REG); +	       timer_base + TIMER_INTVAL_REG(0));  	/* set clock source to HOSC, 16 pre-division */ -	val = readl(timer_base + TIMER0_CTL_REG); +	val = readl(timer_base + TIMER_CTL_REG(0));  	val &= ~(0x07 << 4);  	val &= ~(0x03 << 2);  	val |= (4 << 4) | (1 << 2); -	writel(val, timer_base + TIMER0_CTL_REG); +	writel(val, timer_base + TIMER_CTL_REG(0));  	/* set mode to auto reload */ -	val = readl(timer_base + TIMER0_CTL_REG); -	writel(val | TIMER0_CTL_AUTORELOAD, timer_base + TIMER0_CTL_REG); +	val = readl(timer_base + TIMER_CTL_REG(0)); +	writel(val | TIMER_CTL_AUTORELOAD, timer_base + TIMER_CTL_REG(0)); -	ret = setup_irq(irq, &sunxi_timer_irq); +	ret = setup_irq(irq, &sun4i_timer_irq);  	if (ret)  		pr_warn("failed to setup irq %d\n", irq);  	/* Enable timer0 interrupt */ -	val = readl(timer_base + TIMER_CTL_REG); -	writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG); +	val = readl(timer_base + TIMER_IRQ_EN_REG); +	writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG); -	sunxi_clockevent.cpumask = cpumask_of(0); +	sun4i_clockevent.cpumask = cpumask_of(0); -	clockevents_config_and_register(&sunxi_clockevent, rate / TIMER_SCAL, +	clockevents_config_and_register(&sun4i_clockevent, rate / TIMER_SCAL,  					0x1, 0xff);  } +CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer", +		       sun4i_timer_init); diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 0bde03feb09..ae877b021b5 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -154,29 +154,12 @@ static struct irqaction tegra_timer_irq = {  	.dev_id		= &tegra_clockevent,  }; -static const struct of_device_id timer_match[] __initconst = { -	{ .compatible = "nvidia,tegra20-timer" }, -	{} -}; - -static const struct of_device_id rtc_match[] __initconst = { -	{ .compatible = "nvidia,tegra20-rtc" }, -	{} -}; - -static void __init tegra20_init_timer(void) +static void __init tegra20_init_timer(struct device_node *np)  { -	struct device_node *np;  	struct clk *clk;  	unsigned long rate;  	int ret; -	np = of_find_matching_node(NULL, timer_match); -	if (!np) { -		pr_err("Failed to find timer DT node\n"); -		BUG(); -	} -  	timer_reg_base = of_iomap(np, 0);  	if (!timer_reg_base) {  		pr_err("Can't map timer registers\n"); @@ -189,7 +172,7 @@ static void __init tegra20_init_timer(void)  		BUG();  	} -	clk = clk_get_sys("timer", NULL); +	clk = of_clk_get(np, 0);  	if (IS_ERR(clk)) {  		pr_warn("Unable to get timer clock. Assuming 12Mhz input clock.\n");  		rate = 12000000; @@ -200,30 +183,6 @@ static void __init tegra20_init_timer(void)  	of_node_put(np); -	np = of_find_matching_node(NULL, rtc_match); -	if (!np) { -		pr_err("Failed to find RTC DT node\n"); -		BUG(); -	} - -	rtc_base = of_iomap(np, 0); -	if (!rtc_base) { -		pr_err("Can't map RTC registers"); -		BUG(); -	} - -	/* -	 * rtc registers are used by read_persistent_clock, keep the rtc clock -	 * enabled -	 */ -	clk = clk_get_sys("rtc-tegra", NULL); -	if (IS_ERR(clk)) -		pr_warn("Unable to get rtc-tegra clock\n"); -	else -		clk_prepare_enable(clk); - -	of_node_put(np); -  	switch (rate) {  	case 12000000:  		timer_writel(0x000b, TIMERUS_USEC_CFG); @@ -259,12 +218,34 @@ static void __init tegra20_init_timer(void)  	tegra_clockevent.irq = tegra_timer_irq.irq;  	clockevents_config_and_register(&tegra_clockevent, 1000000,  					0x1, 0x1fffffff); -#ifdef CONFIG_HAVE_ARM_TWD -	twd_local_timer_of_register(); -#endif +} +CLOCKSOURCE_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); + +static void __init tegra20_init_rtc(struct device_node *np) +{ +	struct clk *clk; + +	rtc_base = of_iomap(np, 0); +	if (!rtc_base) { +		pr_err("Can't map RTC registers"); +		BUG(); +	} + +	/* +	 * rtc registers are used by read_persistent_clock, keep the rtc clock +	 * enabled +	 */ +	clk = of_clk_get(np, 0); +	if (IS_ERR(clk)) +		pr_warn("Unable to get rtc-tegra clock\n"); +	else +		clk_prepare_enable(clk); + +	of_node_put(np); +  	register_persistent_clock(NULL, tegra_read_persistent_clock);  } -CLOCKSOURCE_OF_DECLARE(tegra20, "nvidia,tegra20-timer", tegra20_init_timer); +CLOCKSOURCE_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc);  #ifdef CONFIG_PM  static u32 usec_config; diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index 8efc86b5b5d..64f553f04fa 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -129,22 +129,10 @@ static struct irqaction irq = {  	.dev_id  = &clockevent,  }; -static struct of_device_id vt8500_timer_ids[] = { -	{ .compatible = "via,vt8500-timer" }, -	{ } -}; - -static void __init vt8500_timer_init(void) +static void __init vt8500_timer_init(struct device_node *np)  { -	struct device_node *np;  	int timer_irq; -	np = of_find_matching_node(NULL, vt8500_timer_ids); -	if (!np) { -		pr_err("%s: Timer description missing from Device Tree\n", -								__func__); -		return; -	}  	regbase = of_iomap(np, 0);  	if (!regbase) {  		pr_err("%s: Missing iobase description in Device Tree\n", @@ -177,4 +165,4 @@ static void __init vt8500_timer_init(void)  					4, 0xf0000000);  } -CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init) +CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); |