diff mbox

[v2,12/13] ARM: move sp804 and integrator timers to drivers/clocksource

Message ID 1364854883-5961-13-git-send-email-robherring2@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Rob Herring April 1, 2013, 10:21 p.m. UTC
From: Rob Herring <rob.herring@calxeda.com>

Move timer-sp and integrator-ap timer code to drivers/clocksource and
update timer-sp.h and arm_timer.h includes.

This adds CLKSRC_OF support for the integrator-ap timer and removes the
use of "arm,timer-primary" and "arm,timer-secondary" aliases. The timer
selection should not be important as all 3 timers are equal capability.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
---
 arch/arm/Kconfig                                   |    6 -
 arch/arm/common/Makefile                           |    1 -
 arch/arm/mach-integrator/Kconfig                   |    1 +
 arch/arm/mach-integrator/integrator_ap.c           |  170 +-----------------
 arch/arm/mach-integrator/integrator_cp.c           |    5 +-
 arch/arm/mach-realview/core.c                      |    5 +-
 arch/arm/mach-versatile/core.c                     |    4 +-
 arch/arm/mach-vexpress/ct-ca9x4.c                  |    4 +-
 arch/arm/mach-vexpress/v2m.c                       |    4 +-
 drivers/clocksource/Kconfig                        |   12 ++
 drivers/clocksource/Makefile                       |    2 +
 drivers/clocksource/integrator_ap_timer.c          |  189 ++++++++++++++++++++
 .../arm/common => drivers/clocksource}/timer-sp.c  |    6 +-
 .../hardware => include/clocksource}/arm_timer.h   |    4 +-
 include/clocksource/integrator_ap_timer.h          |    7 +
 .../hardware => include/clocksource}/timer-sp.h    |    0
 16 files changed, 226 insertions(+), 194 deletions(-)
 create mode 100644 drivers/clocksource/integrator_ap_timer.c
 rename {arch/arm/common => drivers/clocksource}/timer-sp.c (98%)
 rename {arch/arm/include/asm/hardware => include/clocksource}/arm_timer.h (93%)
 create mode 100644 include/clocksource/integrator_ap_timer.h
 rename {arch/arm/include/asm/hardware => include/clocksource}/timer-sp.h (100%)

diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/include/clocksource/timer-sp.h
similarity index 100%
rename from arch/arm/include/asm/hardware/timer-sp.h
rename to include/clocksource/timer-sp.h

Comments

John Stultz April 1, 2013, 11:26 p.m. UTC | #1
On 04/01/2013 03:21 PM, Rob Herring wrote:
> diff --git a/drivers/clocksource/integrator_ap_timer.c b/drivers/clocksource/integrator_ap_timer.c
> new file mode 100644
> index 0000000..05e6204
> --- /dev/null
> +++ b/drivers/clocksource/integrator_ap_timer.c
[snip]
> +static void __iomem * clkevt_base;
> +
> +/*
> + * IRQ handler for the timer
> + */
> +static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
> +{
> +	struct clock_event_device *evt = dev_id;
> +
> +	/* clear the interrupt */
> +	writel(1, clkevt_base + TIMER_INTCLR);
> +
> +	evt->event_handler(evt);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
> +{
> +	u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
> +
> +	/* Disable timer */
> +	writel(ctrl, clkevt_base + TIMER_CTRL);
> +
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		/* Enable the timer and start the periodic tick */
> +		writel(timer_reload, clkevt_base + TIMER_LOAD);
> +		ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
> +		writel(ctrl, clkevt_base + TIMER_CTRL);
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +		/* Leave the timer disabled, .set_next_event will enable it */
> +		ctrl &= ~TIMER_CTRL_PERIODIC;
> +		writel(ctrl, clkevt_base + TIMER_CTRL);
> +		break;
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +	case CLOCK_EVT_MODE_RESUME:
> +	default:
> +		/* Just leave in disabled state */
> +		break;
> +	}
> +
> +}
> +
> +static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
> +{
> +	unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
> +
> +	writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
> +	writel(next, clkevt_base + TIMER_LOAD);
> +	writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
> +
> +	return 0;
> +}
> +
> +static struct clock_event_device integrator_clockevent = {
> +	.name		= "timer1",
> +	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +	.set_mode	= clkevt_set_mode,
> +	.set_next_event	= clkevt_set_next_event,
> +	.rating		= 300,
> +};
> +
> +static struct irqaction integrator_timer_irq = {
> +	.name		= "timer",
> +	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
> +	.handler	= integrator_timer_interrupt,
> +	.dev_id		= &integrator_clockevent,
> +};
> +
> +void __init integrator_clockevent_init(unsigned long inrate,
> +				       void __iomem *base, int irq)
> +{
> +	unsigned long rate = inrate;
> +	unsigned int ctrl = 0;
> +
> +	clkevt_base = base;
> +	/* Calculate and program a divisor */
> +	if (rate > 0x100000 * HZ) {
> +		rate /= 256;
> +		ctrl |= TIMER_CTRL_DIV256;
> +	} else if (rate > 0x10000 * HZ) {
> +		rate /= 16;
> +		ctrl |= TIMER_CTRL_DIV16;
> +	}
> +	timer_reload = rate / HZ;
> +	writel(ctrl, clkevt_base + TIMER_CTRL);
> +
> +	setup_irq(irq, &integrator_timer_irq);
> +	clockevents_config_and_register(&integrator_clockevent,
> +					rate,
> +					1,
> +					0xffffU);
> +}
> +
> +static void __init ap_of_timer_init(struct device_node *node)
> +{
> +	void __iomem *base;
> +	int irq;
> +	struct clk *clk;
> +	unsigned long rate;
> +
> +	clk = clk_get_sys("ap_timer", NULL);
> +	BUG_ON(IS_ERR(clk));
> +	clk_prepare_enable(clk);
> +	rate = clk_get_rate(clk);
> +
> +	base = of_iomap(node, 0);
> +	if (WARN_ON(!base))
> +		return;
> +
> +	writel(0, base + TIMER_CTRL);
> +
> +	if ((clksrc_base && clkevt_base) || !of_device_is_available(node)) {
> +		iounmap(base);
> +		return;
> +	}
> +
> +	irq = irq_of_parse_and_map(node, 0);
> +	if (!clkevt_base && (irq > 0))
> +		integrator_clockevent_init(rate, base, irq);
> +	else
> +		integrator_clocksource_init(rate, base);
> +}
> +CLOCKSOURCE_OF_DECLARE(integrator_ap, "integrator-timer", ap_of_timer_init);

So, most of the code here is really clockevent code and not clocksource 
code. I realize they were combined in the mach directory you're copying 
them from, but if we're going to move all this code out of the arch 
directory and into drivers/, I'd like to propose we not dump it all into 
drivers/clocksource.

For more context here see:
http://www.spinics.net/lists/arm-kernel/msg234074.html

So unless Thomas objects, would you be willing to break this change up 
adding the relevant irq related bits to a new drivers/clockevents 
directory? You can leave the sched_clock bits to clocksource for now, 
since I think that logic should eventually be integrated with the 
clocksource core.

When you resubmit, please also add Daniel Lezcano 
<daniel.lezcano@linaro.org> to the cc.

thanks
-john
Rob Herring April 2, 2013, 7:49 p.m. UTC | #2
On 04/01/2013 06:26 PM, John Stultz wrote:
> On 04/01/2013 03:21 PM, Rob Herring wrote:
>> diff --git a/drivers/clocksource/integrator_ap_timer.c
>> b/drivers/clocksource/integrator_ap_timer.c
>> new file mode 100644
>> index 0000000..05e6204
>> --- /dev/null
>> +++ b/drivers/clocksource/integrator_ap_timer.c
> [snip]


>> +CLOCKSOURCE_OF_DECLARE(integrator_ap, "integrator-timer",
>> ap_of_timer_init);
> 
> So, most of the code here is really clockevent code and not clocksource
> code. I realize they were combined in the mach directory you're copying
> them from, but if we're going to move all this code out of the arch
> directory and into drivers/, I'd like to propose we not dump it all into
> drivers/clocksource.

Arguably, half the h/w is used for clocksource and half for clockevent
so it is equal. :) The sp804 and integrator are somewhat separated that
carving them up may be possible, but there are examples like i.MX timers
where the implementations are tied more closely together (the clockevent
compare value is the clocksource counter + delta).

Where do I put the init functions which need to know about both?

What about all the other timers that are already in drivers/clocksource?

> 
> For more context here see:
> http://www.spinics.net/lists/arm-kernel/msg234074.html

Seems like this is more a maintainer issue than necessarily what is the
right split of code (not that those are completely unrelated). Perhaps
splitting maintainership between core and drivers is needed. It
definitely seems Thomas cannot keep up with the plethora of ARM related
timers and irqchips getting moved into drivers/.

Rob

> So unless Thomas objects, would you be willing to break this change up
> adding the relevant irq related bits to a new drivers/clockevents
> directory? You can leave the sched_clock bits to clocksource for now,
> since I think that logic should eventually be integrated with the
> clocksource core.
> 
> When you resubmit, please also add Daniel Lezcano
> <daniel.lezcano@linaro.org> to the cc.
> 
> thanks
> -john
John Stultz April 3, 2013, 12:41 a.m. UTC | #3
On 04/02/2013 12:49 PM, Rob Herring wrote:
> On 04/01/2013 06:26 PM, John Stultz wrote:
>> On 04/01/2013 03:21 PM, Rob Herring wrote:
>>> diff --git a/drivers/clocksource/integrator_ap_timer.c
>>> b/drivers/clocksource/integrator_ap_timer.c
>>> new file mode 100644
>>> index 0000000..05e6204
>>> --- /dev/null
>>> +++ b/drivers/clocksource/integrator_ap_timer.c
>> [snip]
>
>>> +CLOCKSOURCE_OF_DECLARE(integrator_ap, "integrator-timer",
>>> ap_of_timer_init);
>> So, most of the code here is really clockevent code and not clocksource
>> code. I realize they were combined in the mach directory you're copying
>> them from, but if we're going to move all this code out of the arch
>> directory and into drivers/, I'd like to propose we not dump it all into
>> drivers/clocksource.
> Arguably, half the h/w is used for clocksource and half for clockevent
> so it is equal. :) The sp804 and integrator are somewhat separated that
> carving them up may be possible, but there are examples like i.MX timers
> where the implementations are tied more closely together (the clockevent
> compare value is the clocksource counter + delta).
>
> Where do I put the init functions which need to know about both?

Either have them init themselves via *_initcall, or call out from one to 
the other?

> What about all the other timers that are already in drivers/clocksource?

I'm hoping to start moving those out soon.


>> For more context here see:
>> http://www.spinics.net/lists/arm-kernel/msg234074.html
> Seems like this is more a maintainer issue than necessarily what is the
> right split of code (not that those are completely unrelated). Perhaps
> splitting maintainership between core and drivers is needed. It
> definitely seems Thomas cannot keep up with the plethora of ARM related
> timers and irqchips getting moved into drivers/.

Well, I'm hoping Daniel can help offload Thomas, but I've still not 
heard back if Thomas is ok with this whole proposal or not.

thanks
-john
Rob Herring April 3, 2013, 2:31 a.m. UTC | #4
On 04/02/2013 07:41 PM, John Stultz wrote:
> On 04/02/2013 12:49 PM, Rob Herring wrote:
>> On 04/01/2013 06:26 PM, John Stultz wrote:
>>> On 04/01/2013 03:21 PM, Rob Herring wrote:
>>>> diff --git a/drivers/clocksource/integrator_ap_timer.c
>>>> b/drivers/clocksource/integrator_ap_timer.c
>>>> new file mode 100644
>>>> index 0000000..05e6204
>>>> --- /dev/null
>>>> +++ b/drivers/clocksource/integrator_ap_timer.c
>>> [snip]
>>
>>>> +CLOCKSOURCE_OF_DECLARE(integrator_ap, "integrator-timer",
>>>> ap_of_timer_init);
>>> So, most of the code here is really clockevent code and not clocksource
>>> code. I realize they were combined in the mach directory you're copying
>>> them from, but if we're going to move all this code out of the arch
>>> directory and into drivers/, I'd like to propose we not dump it all into
>>> drivers/clocksource.
>> Arguably, half the h/w is used for clocksource and half for clockevent
>> so it is equal. :) The sp804 and integrator are somewhat separated that
>> carving them up may be possible, but there are examples like i.MX timers
>> where the implementations are tied more closely together (the clockevent
>> compare value is the clocksource counter + delta).
>>
>> Where do I put the init functions which need to know about both?
> 
> Either have them init themselves via *_initcall, or call out from one to
> the other?

initcalls are too late on ARM. This is why CLOCKSOURCE_OF_DECLARE was
created, but it is tied to 1 init callback per matched DT node. The nice
thing about it is we avoid any headers with arbitrary timer init
functions and data and calls from the platform code in the DT case.

We could also create a CLOCKEVENT_OF_DECLARE and match twice, but then
that is 2 searches thru the DT.

I don't think an undefined interface of shared data that's different for
every timer is a good idea. This is typically the mapped address(es),
clocks, spinlocks, register access functions, misc flags, etc.

>> What about all the other timers that are already in drivers/clocksource?
> 
> I'm hoping to start moving those out soon.

I count 3 clkevt only, 4 clocksource only and 13 drivers with both. How
intertwined the 13 are, I don't know. I think we should get things moved
to a common spot first and look at all the various h/w first before
deciding how to best split things up.

Rob

>>> For more context here see:
>>> http://www.spinics.net/lists/arm-kernel/msg234074.html
>> Seems like this is more a maintainer issue than necessarily what is the
>> right split of code (not that those are completely unrelated). Perhaps
>> splitting maintainership between core and drivers is needed. It
>> definitely seems Thomas cannot keep up with the plethora of ARM related
>> timers and irqchips getting moved into drivers/.
> 
> Well, I'm hoping Daniel can help offload Thomas, but I've still not
> heard back if Thomas is ok with this whole proposal or not.
> 
> thanks
> -john
Linus Walleij April 3, 2013, 4:52 p.m. UTC | #5
On Tue, Apr 2, 2013 at 9:49 PM, Rob Herring <robherring2@gmail.com> wrote:
> On 04/01/2013 06:26 PM, John Stultz wrote:

>> So, most of the code here is really clockevent code and not clocksource
>> code. I realize they were combined in the mach directory you're copying
>> them from, but if we're going to move all this code out of the arch
>> directory and into drivers/, I'd like to propose we not dump it all into
>> drivers/clocksource.
>
> Arguably, half the h/w is used for clocksource and half for clockevent
> so it is equal. :) The sp804 and integrator are somewhat separated that
> carving them up may be possible, but there are examples like i.MX timers
> where the implementations are tied more closely together (the clockevent
> compare value is the clocksource counter + delta).
>
> Where do I put the init functions which need to know about both?
>
> What about all the other timers that are already in drivers/clocksource?

The other day I thought about this because I remembered discussing
it with John, and thinking about how some drivers (like ours) combine
clock source, clock event, sched_clock() hook and delay timers. The
same hardware is incidentally used for all four.

Driver writers really like to think about a driver pertaining to a certain
memory segment in the hardware, and that's causing some strain
here and there in the kernel.

Anyway, I was thinking that the four classes of drivers were somehow
related but not the same thing.

So what about renaming
drivers/clocksource -> drivers/timer

Then create a subdirectory drivers/timer/clocksource
for the pure clocksource code and any drivers falling into that
category.

Thus drivers/timer/clockevent, drivers/timer/schedclock
and drivers/timer/delay can be created to handle specialized
hardware blocks.

But the best thing with that scheme would be that combined
drivers doing several things at once could live directly in
drivers/timer/* and not pollute drivers/clocksource.

Yes/No/Insane?

Yours,
Linus Walleij
Daniel Lezcano April 4, 2013, 11:06 a.m. UTC | #6
On 04/03/2013 06:52 PM, Linus Walleij wrote:
> On Tue, Apr 2, 2013 at 9:49 PM, Rob Herring <robherring2@gmail.com> wrote:
>> On 04/01/2013 06:26 PM, John Stultz wrote:
> 
>>> So, most of the code here is really clockevent code and not clocksource
>>> code. I realize they were combined in the mach directory you're copying
>>> them from, but if we're going to move all this code out of the arch
>>> directory and into drivers/, I'd like to propose we not dump it all into
>>> drivers/clocksource.
>>
>> Arguably, half the h/w is used for clocksource and half for clockevent
>> so it is equal. :) The sp804 and integrator are somewhat separated that
>> carving them up may be possible, but there are examples like i.MX timers
>> where the implementations are tied more closely together (the clockevent
>> compare value is the clocksource counter + delta).
>>
>> Where do I put the init functions which need to know about both?
>>
>> What about all the other timers that are already in drivers/clocksource?
> 
> The other day I thought about this because I remembered discussing
> it with John, and thinking about how some drivers (like ours) combine
> clock source, clock event, sched_clock() hook and delay timers. The
> same hardware is incidentally used for all four.
> 
> Driver writers really like to think about a driver pertaining to a certain
> memory segment in the hardware, and that's causing some strain
> here and there in the kernel.
> 
> Anyway, I was thinking that the four classes of drivers were somehow
> related but not the same thing.
> 
> So what about renaming
> drivers/clocksource -> drivers/timer
> 
> Then create a subdirectory drivers/timer/clocksource
> for the pure clocksource code and any drivers falling into that
> category.
> 
> Thus drivers/timer/clockevent, drivers/timer/schedclock
> and drivers/timer/delay can be created to handle specialized
> hardware blocks.
> 
> But the best thing with that scheme would be that combined
> drivers doing several things at once could live directly in
> drivers/timer/* and not pollute drivers/clocksource.

That looks reasonable.

  -- Daniel
Rob Herring April 10, 2013, 11:23 p.m. UTC | #7
On 04/02/2013 07:41 PM, John Stultz wrote:
> On 04/02/2013 12:49 PM, Rob Herring wrote:
>> On 04/01/2013 06:26 PM, John Stultz wrote:
>>> On 04/01/2013 03:21 PM, Rob Herring wrote:
>>>> diff --git a/drivers/clocksource/integrator_ap_timer.c
>>>> b/drivers/clocksource/integrator_ap_timer.c
>>>> new file mode 100644
>>>> index 0000000..05e6204
>>>> --- /dev/null
>>>> +++ b/drivers/clocksource/integrator_ap_timer.c
>>> [snip]
>>
>>>> +CLOCKSOURCE_OF_DECLARE(integrator_ap, "integrator-timer",
>>>> ap_of_timer_init);
>>> So, most of the code here is really clockevent code and not clocksource
>>> code. I realize they were combined in the mach directory you're copying
>>> them from, but if we're going to move all this code out of the arch
>>> directory and into drivers/, I'd like to propose we not dump it all into
>>> drivers/clocksource.
>> Arguably, half the h/w is used for clocksource and half for clockevent
>> so it is equal. :) The sp804 and integrator are somewhat separated that
>> carving them up may be possible, but there are examples like i.MX timers
>> where the implementations are tied more closely together (the clockevent
>> compare value is the clocksource counter + delta).
>>
>> Where do I put the init functions which need to know about both?
> 
> Either have them init themselves via *_initcall, or call out from one to
> the other?
> 
>> What about all the other timers that are already in drivers/clocksource?
> 
> I'm hoping to start moving those out soon.
> 
> 
>>> For more context here see:
>>> http://www.spinics.net/lists/arm-kernel/msg234074.html
>> Seems like this is more a maintainer issue than necessarily what is the
>> right split of code (not that those are completely unrelated). Perhaps
>> splitting maintainership between core and drivers is needed. It
>> definitely seems Thomas cannot keep up with the plethora of ARM related
>> timers and irqchips getting moved into drivers/.
> 
> Well, I'm hoping Daniel can help offload Thomas, but I've still not
> heard back if Thomas is ok with this whole proposal or not.

I'm waiting until there is some clear direction on how or if to split up
clksrc and clkevt drivers. So I will drop this patch for 3.10 unless you
are okay with moving it to drivers/clocksource first and sorting out how
to split things later.

Rob
Linus Walleij April 11, 2013, 8:33 a.m. UTC | #8
On Thu, Apr 11, 2013 at 1:23 AM, Rob Herring <robherring2@gmail.com> wrote:

> I'm waiting until there is some clear direction on how or if to split up
> clksrc and clkevt drivers. So I will drop this patch for 3.10 unless you
> are okay with moving it to drivers/clocksource first and sorting out how
> to split things later.

No hurries.

What do you think about my proposal to create drivers/timer
and move the clocksource drivers in a subdir there?

Yours,
Linus Walleij
Rob Herring April 11, 2013, 3:12 p.m. UTC | #9
On 04/11/2013 03:33 AM, Linus Walleij wrote:
> On Thu, Apr 11, 2013 at 1:23 AM, Rob Herring <robherring2@gmail.com> wrote:
> 
>> I'm waiting until there is some clear direction on how or if to split up
>> clksrc and clkevt drivers. So I will drop this patch for 3.10 unless you
>> are okay with moving it to drivers/clocksource first and sorting out how
>> to split things later.
> 
> No hurries.
> 
> What do you think about my proposal to create drivers/timer
> and move the clocksource drivers in a subdir there?

I had the exact same idea. I not convinced on how many of the drivers
could be split though. So if everything just ends up in drivers/timers
rather than drivers/timers/ subdirectories, we haven't really
accomplished anything.

Rob
diff mbox

Patch

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 10e3053..982076c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1170,12 +1170,6 @@  config PLAT_PXA
 config PLAT_VERSATILE
 	bool
 
-config ARM_TIMER_SP804
-	bool
-	select CLKSRC_MMIO
-	select CLKSRC_OF if OF
-	select HAVE_SCHED_CLOCK
-
 source arch/arm/mm/Kconfig
 
 config ARM_NR_BANKS
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index dc8dd0d..5a4cc1a 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -10,4 +10,3 @@  obj-$(CONFIG_SHARP_LOCOMO)	+= locomo.o
 obj-$(CONFIG_SHARP_PARAM)	+= sharpsl_param.o
 obj-$(CONFIG_SHARP_SCOOP)	+= scoop.o
 obj-$(CONFIG_PCI_HOST_ITE8152)  += it8152.o
-obj-$(CONFIG_ARM_TIMER_SP804)	+= timer-sp.o
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig
index abeff25..c5e4ff3 100644
--- a/arch/arm/mach-integrator/Kconfig
+++ b/arch/arm/mach-integrator/Kconfig
@@ -5,6 +5,7 @@  menu "Integrator Options"
 config ARCH_INTEGRATOR_AP
 	bool "Support Integrator/AP and Integrator/PP2 platforms"
 	select CLKSRC_MMIO
+	select INTEGRATOR_AP_TIMER
 	select MIGHT_HAVE_PCI
 	select SERIAL_AMBA_PL010
 	select SERIAL_AMBA_PL010_CONSOLE
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index ea96144..c364e8e 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -27,8 +27,6 @@ 
 #include <linux/syscore_ops.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/kmi.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irqchip/versatile-fpga.h>
@@ -41,15 +39,15 @@ 
 #include <linux/stat.h>
 #include <linux/sys_soc.h>
 #include <linux/termios.h>
+#include <clocksource/arm_timer.h>
+#include <clocksource/integrator_ap_timer.h>
 #include <video/vga.h>
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
-#include <asm/hardware/arm_timer.h>
 #include <asm/setup.h>
 #include <asm/param.h>		/* HZ */
 #include <asm/mach-types.h>
-#include <asm/sched_clock.h>
 
 #include <mach/lm.h>
 #include <mach/irqs.h>
@@ -58,7 +56,6 @@ 
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
 #include <asm/mach/pci.h>
-#include <asm/mach/time.h>
 
 #include "common.h"
 
@@ -296,174 +293,12 @@  struct amba_pl010_data ap_uart_data = {
 #define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE)
 #define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE)
 
-static unsigned long timer_reload;
-
-static u32 notrace integrator_read_sched_clock(void)
-{
-	return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE);
-}
-
-static void integrator_clocksource_init(unsigned long inrate,
-					void __iomem *base)
-{
-	u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
-	unsigned long rate = inrate;
-
-	if (rate >= 1500000) {
-		rate /= 16;
-		ctrl |= TIMER_CTRL_DIV16;
-	}
-
-	writel(0xffff, base + TIMER_LOAD);
-	writel(ctrl, base + TIMER_CTRL);
-
-	clocksource_mmio_init(base + TIMER_VALUE, "timer2",
-			rate, 200, 16, clocksource_mmio_readl_down);
-	setup_sched_clock(integrator_read_sched_clock, 16, rate);
-}
-
-static void __iomem * clkevt_base;
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
-{
-	struct clock_event_device *evt = dev_id;
-
-	/* clear the interrupt */
-	writel(1, clkevt_base + TIMER_INTCLR);
-
-	evt->event_handler(evt);
-
-	return IRQ_HANDLED;
-}
-
-static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
-{
-	u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
-
-	/* Disable timer */
-	writel(ctrl, clkevt_base + TIMER_CTRL);
-
-	switch (mode) {
-	case CLOCK_EVT_MODE_PERIODIC:
-		/* Enable the timer and start the periodic tick */
-		writel(timer_reload, clkevt_base + TIMER_LOAD);
-		ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
-		writel(ctrl, clkevt_base + TIMER_CTRL);
-		break;
-	case CLOCK_EVT_MODE_ONESHOT:
-		/* Leave the timer disabled, .set_next_event will enable it */
-		ctrl &= ~TIMER_CTRL_PERIODIC;
-		writel(ctrl, clkevt_base + TIMER_CTRL);
-		break;
-	case CLOCK_EVT_MODE_UNUSED:
-	case CLOCK_EVT_MODE_SHUTDOWN:
-	case CLOCK_EVT_MODE_RESUME:
-	default:
-		/* Just leave in disabled state */
-		break;
-	}
-
-}
-
-static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
-{
-	unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
-
-	writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
-	writel(next, clkevt_base + TIMER_LOAD);
-	writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
-
-	return 0;
-}
-
-static struct clock_event_device integrator_clockevent = {
-	.name		= "timer1",
-	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-	.set_mode	= clkevt_set_mode,
-	.set_next_event	= clkevt_set_next_event,
-	.rating		= 300,
-};
-
-static struct irqaction integrator_timer_irq = {
-	.name		= "timer",
-	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-	.handler	= integrator_timer_interrupt,
-	.dev_id		= &integrator_clockevent,
-};
-
-static void integrator_clockevent_init(unsigned long inrate,
-				void __iomem *base, int irq)
-{
-	unsigned long rate = inrate;
-	unsigned int ctrl = 0;
-
-	clkevt_base = base;
-	/* Calculate and program a divisor */
-	if (rate > 0x100000 * HZ) {
-		rate /= 256;
-		ctrl |= TIMER_CTRL_DIV256;
-	} else if (rate > 0x10000 * HZ) {
-		rate /= 16;
-		ctrl |= TIMER_CTRL_DIV16;
-	}
-	timer_reload = rate / HZ;
-	writel(ctrl, clkevt_base + TIMER_CTRL);
-
-	setup_irq(irq, &integrator_timer_irq);
-	clockevents_config_and_register(&integrator_clockevent,
-					rate,
-					1,
-					0xffffU);
-}
-
 void __init ap_init_early(void)
 {
 }
 
 #ifdef CONFIG_OF
 
-static void __init ap_of_timer_init(void)
-{
-	struct device_node *node;
-	const char *path;
-	void __iomem *base;
-	int err;
-	int irq;
-	struct clk *clk;
-	unsigned long rate;
-
-	clk = clk_get_sys("ap_timer", NULL);
-	BUG_ON(IS_ERR(clk));
-	clk_prepare_enable(clk);
-	rate = clk_get_rate(clk);
-
-	err = of_property_read_string(of_aliases,
-				"arm,timer-primary", &path);
-	if (WARN_ON(err))
-		return;
-	node = of_find_node_by_path(path);
-	base = of_iomap(node, 0);
-	if (WARN_ON(!base))
-		return;
-	writel(0, base + TIMER_CTRL);
-	integrator_clocksource_init(rate, base);
-
-	err = of_property_read_string(of_aliases,
-				"arm,timer-secondary", &path);
-	if (WARN_ON(err))
-		return;
-	node = of_find_node_by_path(path);
-	base = of_iomap(node, 0);
-	if (WARN_ON(!base))
-		return;
-	irq = irq_of_parse_and_map(node, 0);
-	writel(0, base + TIMER_CTRL);
-	integrator_clockevent_init(rate, base, irq);
-}
-
 static const struct of_device_id fpga_irq_of_match[] __initconst = {
 	{ .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, },
 	{ /* Sentinel */ }
@@ -582,7 +417,6 @@  DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)")
 	.init_early	= ap_init_early,
 	.init_irq	= ap_init_irq_of,
 	.handle_irq	= fpga_handle_irq,
-	.init_time	= ap_of_timer_init,
 	.init_machine	= ap_init_of,
 	.restart	= integrator_restart,
 	.dt_compat      = ap_dt_board_compat,
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 5781f3c..19e2497 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -28,12 +28,13 @@ 
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/sys_soc.h>
+#include <clocksource/arm_timer.h>
+#include <clocksource/timer-sp.h>
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
-#include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst.h>
 
 #include <mach/cm.h>
@@ -45,8 +46,6 @@ 
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 
-#include <asm/hardware/timer-sp.h>
-
 #include <plat/clcd.h>
 #include <plat/sched_clock.h>
 
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 1d5ee5c..ac59770 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -31,21 +31,20 @@ 
 #include <linux/amba/mmci.h>
 #include <linux/gfp.h>
 #include <linux/mtd/physmap.h>
+#include <clocksource/arm_timer.h>
+#include <clocksource/timer-sp.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
-#include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
 
-
 #include <mach/platform.h>
 #include <mach/irqs.h>
-#include <asm/hardware/timer-sp.h>
 
 #include <plat/clcd.h>
 #include <plat/sched_clock.h>
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 54bb80b..84f26c7 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -38,9 +38,10 @@ 
 #include <linux/clkdev.h>
 #include <linux/mtd/physmap.h>
 #include <linux/bitops.h>
+#include <clocksource/arm_timer.h>
+#include <clocksource/timer-sp.h>
 
 #include <asm/irq.h>
-#include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst.h>
 #include <asm/mach-types.h>
 
@@ -50,7 +51,6 @@ 
 #include <asm/mach/map.h>
 #include <mach/hardware.h>
 #include <mach/platform.h>
-#include <asm/hardware/timer-sp.h>
 
 #include <plat/clcd.h>
 #include <plat/sched_clock.h>
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 6f34497..8cce326 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -11,16 +11,14 @@ 
 #include <linux/clkdev.h>
 #include <linux/vexpress.h>
 #include <linux/irqchip/arm-gic.h>
+#include <clocksource/timer-sp.h>
 
-#include <asm/hardware/arm_timer.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/smp_scu.h>
 #include <asm/smp_twd.h>
 
 #include <mach/ct-ca9x4.h>
 
-#include <asm/hardware/timer-sp.h>
-
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 09e571d..dc15485 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -23,15 +23,15 @@ 
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/vexpress.h>
+#include <clocksource/arm_timer.h>
+#include <clocksource/timer-sp.h>
 
 #include <asm/mach-types.h>
 #include <asm/sizes.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
-#include <asm/hardware/arm_timer.h>
 #include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/timer-sp.h>
 
 #include <mach/ct-ca9x4.h>
 #include <mach/motherboard.h>
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index d98e7e1..00aa4cd 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -25,6 +25,18 @@  config DW_APB_TIMER_OF
 config ARMADA_370_XP_TIMER
 	bool
 
+config ARM_TIMER_SP804
+	bool
+	depends on ARM
+	select CLKSRC_MMIO
+	select CLKSRC_OF if OF
+	select HAVE_SCHED_CLOCK
+
+config INTEGRATOR_AP_TIMER
+	bool
+	depends on ARM
+	select CLKSRC_OF if OF
+
 config SUNXI_TIMER
 	bool
 
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 4d8283a..9f3b62b 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -14,8 +14,10 @@  obj-$(CONFIG_DW_APB_TIMER)	+= dw_apb_timer.o
 obj-$(CONFIG_DW_APB_TIMER_OF)	+= dw_apb_timer_of.o
 obj-$(CONFIG_CLKSRC_NOMADIK_MTU)	+= nomadik-mtu.o
 obj-$(CONFIG_CLKSRC_DBX500_PRCMU)	+= clksrc-dbx500-prcmu.o
+obj-$(CONFIG_ARM_TIMER_SP804)	+= timer-sp.o
 obj-$(CONFIG_ARMADA_370_XP_TIMER)	+= time-armada-370-xp.o
 obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o
+obj-$(CONFIG_INTEGRATOR_AP_TIMER)	+= integrator_ap_timer.o
 obj-$(CONFIG_SUNXI_TIMER)	+= sunxi_timer.o
 obj-$(CONFIG_ARCH_TEGRA)	+= tegra20_timer.o
 obj-$(CONFIG_VT8500_TIMER)	+= vt8500_timer.o
diff --git a/drivers/clocksource/integrator_ap_timer.c b/drivers/clocksource/integrator_ap_timer.c
new file mode 100644
index 0000000..05e6204
--- /dev/null
+++ b/drivers/clocksource/integrator_ap_timer.c
@@ -0,0 +1,189 @@ 
+/*
+ *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <clocksource/timer-sp.h>
+#include <clocksource/arm_timer.h>
+
+#include <asm/sched_clock.h>
+
+static unsigned long timer_reload;
+static void __iomem *clksrc_base;
+
+static u32 notrace integrator_read_sched_clock(void)
+{
+	return -readl(clksrc_base + TIMER_VALUE);
+}
+
+void __init integrator_clocksource_init(unsigned long inrate,
+					void __iomem *base)
+{
+	u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
+	unsigned long rate = inrate;
+
+	clksrc_base = base;
+
+	if (rate >= 1500000) {
+		rate /= 16;
+		ctrl |= TIMER_CTRL_DIV16;
+	}
+
+	writel(0xffff, base + TIMER_LOAD);
+	writel(ctrl, base + TIMER_CTRL);
+
+	clocksource_mmio_init(base + TIMER_VALUE, "timer2",
+			rate, 200, 16, clocksource_mmio_readl_down);
+	setup_sched_clock(integrator_read_sched_clock, 16, rate);
+}
+
+static void __iomem * clkevt_base;
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+
+	/* clear the interrupt */
+	writel(1, clkevt_base + TIMER_INTCLR);
+
+	evt->event_handler(evt);
+
+	return IRQ_HANDLED;
+}
+
+static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
+{
+	u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
+
+	/* Disable timer */
+	writel(ctrl, clkevt_base + TIMER_CTRL);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		/* Enable the timer and start the periodic tick */
+		writel(timer_reload, clkevt_base + TIMER_LOAD);
+		ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
+		writel(ctrl, clkevt_base + TIMER_CTRL);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		/* Leave the timer disabled, .set_next_event will enable it */
+		ctrl &= ~TIMER_CTRL_PERIODIC;
+		writel(ctrl, clkevt_base + TIMER_CTRL);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_RESUME:
+	default:
+		/* Just leave in disabled state */
+		break;
+	}
+
+}
+
+static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
+{
+	unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
+
+	writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
+	writel(next, clkevt_base + TIMER_LOAD);
+	writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
+
+	return 0;
+}
+
+static struct clock_event_device integrator_clockevent = {
+	.name		= "timer1",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.set_mode	= clkevt_set_mode,
+	.set_next_event	= clkevt_set_next_event,
+	.rating		= 300,
+};
+
+static struct irqaction integrator_timer_irq = {
+	.name		= "timer",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler	= integrator_timer_interrupt,
+	.dev_id		= &integrator_clockevent,
+};
+
+void __init integrator_clockevent_init(unsigned long inrate,
+				       void __iomem *base, int irq)
+{
+	unsigned long rate = inrate;
+	unsigned int ctrl = 0;
+
+	clkevt_base = base;
+	/* Calculate and program a divisor */
+	if (rate > 0x100000 * HZ) {
+		rate /= 256;
+		ctrl |= TIMER_CTRL_DIV256;
+	} else if (rate > 0x10000 * HZ) {
+		rate /= 16;
+		ctrl |= TIMER_CTRL_DIV16;
+	}
+	timer_reload = rate / HZ;
+	writel(ctrl, clkevt_base + TIMER_CTRL);
+
+	setup_irq(irq, &integrator_timer_irq);
+	clockevents_config_and_register(&integrator_clockevent,
+					rate,
+					1,
+					0xffffU);
+}
+
+static void __init ap_of_timer_init(struct device_node *node)
+{
+	void __iomem *base;
+	int irq;
+	struct clk *clk;
+	unsigned long rate;
+
+	clk = clk_get_sys("ap_timer", NULL);
+	BUG_ON(IS_ERR(clk));
+	clk_prepare_enable(clk);
+	rate = clk_get_rate(clk);
+
+	base = of_iomap(node, 0);
+	if (WARN_ON(!base))
+		return;
+
+	writel(0, base + TIMER_CTRL);
+
+	if ((clksrc_base && clkevt_base) || !of_device_is_available(node)) {
+		iounmap(base);
+		return;
+	}
+
+	irq = irq_of_parse_and_map(node, 0);
+	if (!clkevt_base && (irq > 0))
+		integrator_clockevent_init(rate, base, irq);
+	else
+		integrator_clocksource_init(rate, base);
+}
+CLOCKSOURCE_OF_DECLARE(integrator_ap, "integrator-timer", ap_of_timer_init);
diff --git a/arch/arm/common/timer-sp.c b/drivers/clocksource/timer-sp.c
similarity index 98%
rename from arch/arm/common/timer-sp.c
rename to drivers/clocksource/timer-sp.c
index ddc7407..b0fc7f0 100644
--- a/arch/arm/common/timer-sp.c
+++ b/drivers/clocksource/timer-sp.c
@@ -1,6 +1,4 @@ 
 /*
- *  linux/arch/arm/common/timer-sp.c
- *
  *  Copyright (C) 1999 - 2003 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd
  *
@@ -28,10 +26,10 @@ 
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <clocksource/arm_timer.h>
+#include <clocksource/timer-sp.h>
 
 #include <asm/sched_clock.h>
-#include <asm/hardware/arm_timer.h>
-#include <asm/hardware/timer-sp.h>
 
 static long __init sp804_get_clock_rate(struct clk *clk)
 {
diff --git a/arch/arm/include/asm/hardware/arm_timer.h b/include/clocksource/arm_timer.h
similarity index 93%
rename from arch/arm/include/asm/hardware/arm_timer.h
rename to include/clocksource/arm_timer.h
index d6030ff..f4a443a 100644
--- a/arch/arm/include/asm/hardware/arm_timer.h
+++ b/include/clocksource/arm_timer.h
@@ -1,5 +1,5 @@ 
-#ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H
-#define __ASM_ARM_HARDWARE_ARM_TIMER_H
+#ifndef __CLOCKSOURCE_ARM_TIMER_H
+#define __CLOCKSOURCE_ARM_TIMER_H
 
 /*
  * ARM timer implementation, found in Integrator, Versatile and Realview
diff --git a/include/clocksource/integrator_ap_timer.h b/include/clocksource/integrator_ap_timer.h
new file mode 100644
index 0000000..2f585fc
--- /dev/null
+++ b/include/clocksource/integrator_ap_timer.h
@@ -0,0 +1,7 @@ 
+#ifndef __CLOCKSOURCE_INTEGRATOR_AP_TIMER
+#define __CLOCKSOURCE_INTEGRATOR_AP_TIMER
+
+void integrator_clocksource_init(unsigned long inrate, void __iomem *base);
+void integrator_clockevent_init(unsigned long inrate, void __iomem *base, int irq);
+
+#endif