aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/versatile-sysreg.txt10
-rw-r--r--Documentation/devicetree/bindings/timer/digicolor-timer.txt18
-rw-r--r--Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt18
-rw-r--r--MAINTAINERS2
-rw-r--r--arch/arm/boot/dts/versatile-ab.dts5
-rw-r--r--arch/arm/mach-rockchip/Kconfig1
-rw-r--r--drivers/clocksource/Kconfig17
-rw-r--r--drivers/clocksource/Makefile5
-rw-r--r--drivers/clocksource/asm9260_timer.c220
-rw-r--r--drivers/clocksource/rockchip_timer.c180
-rw-r--r--drivers/clocksource/timer-atlas7.c (renamed from drivers/clocksource/timer-marco.c)15
-rw-r--r--drivers/clocksource/timer-digicolor.c199
-rw-r--r--drivers/clocksource/versatile.c4
13 files changed, 683 insertions, 11 deletions
diff --git a/Documentation/devicetree/bindings/arm/versatile-sysreg.txt b/Documentation/devicetree/bindings/arm/versatile-sysreg.txt
new file mode 100644
index 000000000000..a4f15262d717
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/versatile-sysreg.txt
@@ -0,0 +1,10 @@
1ARM Versatile system registers
2--------------------------------------
3
4This is a system control registers block, providing multiple low level
5platform functions like board detection and identification, software
6interrupt generation, MMC and NOR Flash control etc.
7
8Required node properties:
9- compatible value : = "arm,versatile-sysreg", "syscon"
10- reg : physical base address and the size of the registers window
diff --git a/Documentation/devicetree/bindings/timer/digicolor-timer.txt b/Documentation/devicetree/bindings/timer/digicolor-timer.txt
new file mode 100644
index 000000000000..d1b659bbc29f
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/digicolor-timer.txt
@@ -0,0 +1,18 @@
1Conexant Digicolor SoCs Timer Controller
2
3Required properties:
4
5- compatible : should be "cnxt,cx92755-timer"
6- reg : Specifies base physical address and size of the "Agent Communication"
7 timer registers
8- interrupts : Contains 8 interrupts, one for each timer
9- clocks: phandle to the main clock
10
11Example:
12
13 timer@f0000fc0 {
14 compatible = "cnxt,cx92755-timer";
15 reg = <0xf0000fc0 0x40>;
16 interrupts = <19>, <31>, <34>, <35>, <52>, <53>, <54>, <55>;
17 clocks = <&main_clk>;
18 };
diff --git a/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt b/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt
new file mode 100644
index 000000000000..87f0b0042bae
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt
@@ -0,0 +1,18 @@
1Rockchip rk3288 timer
2
3Required properties:
4- compatible: shall be "rockchip,rk3288-timer"
5- reg: base address of the timer register starting with TIMERS CONTROL register
6- interrupts: should contain the interrupts for Timer0
7- clocks : must contain an entry for each entry in clock-names
8- clock-names : must include the following entries:
9 "timer", "pclk"
10
11Example:
12 timer: timer@ff810000 {
13 compatible = "rockchip,rk3288-timer";
14 reg = <0xff810000 0x20>;
15 interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
16 clocks = <&xin24m>, <&cru PCLK_TIMER>;
17 clock-names = "timer", "pclk";
18 };
diff --git a/MAINTAINERS b/MAINTAINERS
index 348f5c16ef50..b663e3590bd4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -974,7 +974,7 @@ S: Maintained
974F: arch/arm/mach-prima2/ 974F: arch/arm/mach-prima2/
975F: drivers/clk/sirf/ 975F: drivers/clk/sirf/
976F: drivers/clocksource/timer-prima2.c 976F: drivers/clocksource/timer-prima2.c
977F: drivers/clocksource/timer-marco.c 977F: drivers/clocksource/timer-atlas7.c
978N: [^a-z]sirf 978N: [^a-z]sirf
979 979
980ARM/EBSA110 MACHINE SUPPORT 980ARM/EBSA110 MACHINE SUPPORT
diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts
index 27d0d9c8adf3..01f40197ea13 100644
--- a/arch/arm/boot/dts/versatile-ab.dts
+++ b/arch/arm/boot/dts/versatile-ab.dts
@@ -252,6 +252,11 @@
252 #size-cells = <1>; 252 #size-cells = <1>;
253 ranges = <0 0x10000000 0x10000>; 253 ranges = <0 0x10000000 0x10000>;
254 254
255 sysreg@0 {
256 compatible = "arm,versatile-sysreg", "syscon";
257 reg = <0x00000 0x1000>;
258 };
259
255 aaci@4000 { 260 aaci@4000 {
256 compatible = "arm,primecell"; 261 compatible = "arm,primecell";
257 reg = <0x4000 0x1000>; 262 reg = <0x4000 0x1000>;
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index ac5803cac98d..5078932c1683 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -11,6 +11,7 @@ config ARCH_ROCKCHIP
11 select HAVE_ARM_SCU if SMP 11 select HAVE_ARM_SCU if SMP
12 select HAVE_ARM_TWD if SMP 12 select HAVE_ARM_TWD if SMP
13 select DW_APB_TIMER_OF 13 select DW_APB_TIMER_OF
14 select ROCKCHIP_TIMER
14 select ARM_GLOBAL_TIMER 15 select ARM_GLOBAL_TIMER
15 select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK 16 select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
16 help 17 help
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 8a1479fc6479..717f40e875fc 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -18,6 +18,9 @@ config CLKBLD_I8253
18config CLKSRC_MMIO 18config CLKSRC_MMIO
19 bool 19 bool
20 20
21config DIGICOLOR_TIMER
22 bool
23
21config DW_APB_TIMER 24config DW_APB_TIMER
22 bool 25 bool
23 26
@@ -26,6 +29,10 @@ config DW_APB_TIMER_OF
26 select DW_APB_TIMER 29 select DW_APB_TIMER
27 select CLKSRC_OF 30 select CLKSRC_OF
28 31
32config ROCKCHIP_TIMER
33 bool
34 select CLKSRC_OF
35
29config ARMADA_370_XP_TIMER 36config ARMADA_370_XP_TIMER
30 bool 37 bool
31 select CLKSRC_OF 38 select CLKSRC_OF
@@ -236,4 +243,14 @@ config CLKSRC_PXA
236 This enables OST0 support available on PXA and SA-11x0 243 This enables OST0 support available on PXA and SA-11x0
237 platforms. 244 platforms.
238 245
246config ASM9260_TIMER
247 bool "Alphascale ASM9260 timer driver"
248 depends on GENERIC_CLOCKEVENTS
249 select CLKSRC_MMIO
250 select CLKSRC_OF
251 default y if MACH_ASM9260
252 help
253 This enables build of a clocksource and clockevent driver for
254 the 32-bit System Timer hardware available on a Alphascale ASM9260.
255
239endmenu 256endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index aa526f4bd3cf..3359121570c7 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -10,15 +10,17 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o
10obj-$(CONFIG_EM_TIMER_STI) += em_sti.o 10obj-$(CONFIG_EM_TIMER_STI) += em_sti.o
11obj-$(CONFIG_CLKBLD_I8253) += i8253.o 11obj-$(CONFIG_CLKBLD_I8253) += i8253.o
12obj-$(CONFIG_CLKSRC_MMIO) += mmio.o 12obj-$(CONFIG_CLKSRC_MMIO) += mmio.o
13obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o
13obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o 14obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
14obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o 15obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
16obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
15obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o 17obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
16obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o 18obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
17obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o 19obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
18obj-$(CONFIG_ORION_TIMER) += time-orion.o 20obj-$(CONFIG_ORION_TIMER) += time-orion.o
19obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o 21obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
20obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o 22obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o
21obj-$(CONFIG_ARCH_MARCO) += timer-marco.o 23obj-$(CONFIG_ARCH_ATLAS7) += timer-atlas7.o
22obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o 24obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o
23obj-$(CONFIG_ARCH_MXS) += mxs_timer.o 25obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
24obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o 26obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o
@@ -48,3 +50,4 @@ obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
48obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o 50obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o
49obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o 51obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
50obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o 52obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o
53obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o
diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c
new file mode 100644
index 000000000000..2c9c993727c8
--- /dev/null
+++ b/drivers/clocksource/asm9260_timer.c
@@ -0,0 +1,220 @@
1/*
2 * Copyright (C) 2014 Oleksij Rempel <linux@rempel-privat.de>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 */
9
10#include <linux/kernel.h>
11#include <linux/init.h>
12#include <linux/interrupt.h>
13#include <linux/sched.h>
14#include <linux/clk.h>
15#include <linux/clocksource.h>
16#include <linux/clockchips.h>
17#include <linux/io.h>
18#include <linux/of.h>
19#include <linux/of_address.h>
20#include <linux/of_irq.h>
21#include <linux/bitops.h>
22
23#define DRIVER_NAME "asm9260-timer"
24
25/*
26 * this device provide 4 offsets for each register:
27 * 0x0 - plain read write mode
28 * 0x4 - set mode, OR logic.
29 * 0x8 - clr mode, XOR logic.
30 * 0xc - togle mode.
31 */
32#define SET_REG 4
33#define CLR_REG 8
34
35#define HW_IR 0x0000 /* RW. Interrupt */
36#define BM_IR_CR0 BIT(4)
37#define BM_IR_MR3 BIT(3)
38#define BM_IR_MR2 BIT(2)
39#define BM_IR_MR1 BIT(1)
40#define BM_IR_MR0 BIT(0)
41
42#define HW_TCR 0x0010 /* RW. Timer controller */
43/* BM_C*_RST
44 * Timer Counter and the Prescale Counter are synchronously reset on the
45 * next positive edge of PCLK. The counters remain reset until TCR[1] is
46 * returned to zero. */
47#define BM_C3_RST BIT(7)
48#define BM_C2_RST BIT(6)
49#define BM_C1_RST BIT(5)
50#define BM_C0_RST BIT(4)
51/* BM_C*_EN
52 * 1 - Timer Counter and Prescale Counter are enabled for counting
53 * 0 - counters are disabled */
54#define BM_C3_EN BIT(3)
55#define BM_C2_EN BIT(2)
56#define BM_C1_EN BIT(1)
57#define BM_C0_EN BIT(0)
58
59#define HW_DIR 0x0020 /* RW. Direction? */
60/* 00 - count up
61 * 01 - count down
62 * 10 - ?? 2^n/2 */
63#define BM_DIR_COUNT_UP 0
64#define BM_DIR_COUNT_DOWN 1
65#define BM_DIR0_SHIFT 0
66#define BM_DIR1_SHIFT 4
67#define BM_DIR2_SHIFT 8
68#define BM_DIR3_SHIFT 12
69#define BM_DIR_DEFAULT (BM_DIR_COUNT_UP << BM_DIR0_SHIFT | \
70 BM_DIR_COUNT_UP << BM_DIR1_SHIFT | \
71 BM_DIR_COUNT_UP << BM_DIR2_SHIFT | \
72 BM_DIR_COUNT_UP << BM_DIR3_SHIFT)
73
74#define HW_TC0 0x0030 /* RO. Timer counter 0 */
75/* HW_TC*. Timer counter owerflow (0xffff.ffff to 0x0000.0000) do not generate
76 * interrupt. This registers can be used to detect overflow */
77#define HW_TC1 0x0040
78#define HW_TC2 0x0050
79#define HW_TC3 0x0060
80
81#define HW_PR 0x0070 /* RW. prescaler */
82#define BM_PR_DISABLE 0
83#define HW_PC 0x0080 /* RO. Prescaler counter */
84#define HW_MCR 0x0090 /* RW. Match control */
85/* enable interrupt on match */
86#define BM_MCR_INT_EN(n) (1 << (n * 3 + 0))
87/* enable TC reset on match */
88#define BM_MCR_RES_EN(n) (1 << (n * 3 + 1))
89/* enable stop TC on match */
90#define BM_MCR_STOP_EN(n) (1 << (n * 3 + 2))
91
92#define HW_MR0 0x00a0 /* RW. Match reg */
93#define HW_MR1 0x00b0
94#define HW_MR2 0x00C0
95#define HW_MR3 0x00D0
96
97#define HW_CTCR 0x0180 /* Counter control */
98#define BM_CTCR0_SHIFT 0
99#define BM_CTCR1_SHIFT 2
100#define BM_CTCR2_SHIFT 4
101#define BM_CTCR3_SHIFT 6
102#define BM_CTCR_TM 0 /* Timer mode. Every rising PCLK edge. */
103#define BM_CTCR_DEFAULT (BM_CTCR_TM << BM_CTCR0_SHIFT | \
104 BM_CTCR_TM << BM_CTCR1_SHIFT | \
105 BM_CTCR_TM << BM_CTCR2_SHIFT | \
106 BM_CTCR_TM << BM_CTCR3_SHIFT)
107
108static struct asm9260_timer_priv {
109 void __iomem *base;
110 unsigned long ticks_per_jiffy;
111} priv;
112
113static int asm9260_timer_set_next_event(unsigned long delta,
114 struct clock_event_device *evt)
115{
116 /* configure match count for TC0 */
117 writel_relaxed(delta, priv.base + HW_MR0);
118 /* enable TC0 */
119 writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG);
120 return 0;
121}
122
123static void asm9260_timer_set_mode(enum clock_event_mode mode,
124 struct clock_event_device *evt)
125{
126 /* stop timer0 */
127 writel_relaxed(BM_C0_EN, priv.base + HW_TCR + CLR_REG);
128
129 switch (mode) {
130 case CLOCK_EVT_MODE_PERIODIC:
131 /* disable reset and stop on match */
132 writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0),
133 priv.base + HW_MCR + CLR_REG);
134 /* configure match count for TC0 */
135 writel_relaxed(priv.ticks_per_jiffy, priv.base + HW_MR0);
136 /* enable TC0 */
137 writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG);
138 break;
139 case CLOCK_EVT_MODE_ONESHOT:
140 /* enable reset and stop on match */
141 writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0),
142 priv.base + HW_MCR + SET_REG);
143 break;
144 default:
145 break;
146 }
147}
148
149static struct clock_event_device event_dev = {
150 .name = DRIVER_NAME,
151 .rating = 200,
152 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
153 .set_next_event = asm9260_timer_set_next_event,
154 .set_mode = asm9260_timer_set_mode,
155};
156
157static irqreturn_t asm9260_timer_interrupt(int irq, void *dev_id)
158{
159 struct clock_event_device *evt = dev_id;
160
161 evt->event_handler(evt);
162
163 writel_relaxed(BM_IR_MR0, priv.base + HW_IR);
164
165 return IRQ_HANDLED;
166}
167
168/*
169 * ---------------------------------------------------------------------------
170 * Timer initialization
171 * ---------------------------------------------------------------------------
172 */
173static void __init asm9260_timer_init(struct device_node *np)
174{
175 int irq;
176 struct clk *clk;
177 int ret;
178 unsigned long rate;
179
180 priv.base = of_io_request_and_map(np, 0, np->name);
181 if (!priv.base)
182 panic("%s: unable to map resource", np->name);
183
184 clk = of_clk_get(np, 0);
185
186 ret = clk_prepare_enable(clk);
187 if (ret)
188 panic("Failed to enable clk!\n");
189
190 irq = irq_of_parse_and_map(np, 0);
191 ret = request_irq(irq, asm9260_timer_interrupt, IRQF_TIMER,
192 DRIVER_NAME, &event_dev);
193 if (ret)
194 panic("Failed to setup irq!\n");
195
196 /* set all timers for count-up */
197 writel_relaxed(BM_DIR_DEFAULT, priv.base + HW_DIR);
198 /* disable divider */
199 writel_relaxed(BM_PR_DISABLE, priv.base + HW_PR);
200 /* make sure all timers use every rising PCLK edge. */
201 writel_relaxed(BM_CTCR_DEFAULT, priv.base + HW_CTCR);
202 /* enable interrupt for TC0 and clean setting for all other lines */
203 writel_relaxed(BM_MCR_INT_EN(0) , priv.base + HW_MCR);
204
205 rate = clk_get_rate(clk);
206 clocksource_mmio_init(priv.base + HW_TC1, DRIVER_NAME, rate,
207 200, 32, clocksource_mmio_readl_up);
208
209 /* Seems like we can't use counter without match register even if
210 * actions for MR are disabled. So, set MR to max value. */
211 writel_relaxed(0xffffffff, priv.base + HW_MR1);
212 /* enable TC1 */
213 writel_relaxed(BM_C1_EN, priv.base + HW_TCR + SET_REG);
214
215 priv.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
216 event_dev.cpumask = cpumask_of(0);
217 clockevents_config_and_register(&event_dev, rate, 0x2c00, 0xfffffffe);
218}
219CLOCKSOURCE_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer",
220 asm9260_timer_init);
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
new file mode 100644
index 000000000000..a35993bafb20
--- /dev/null
+++ b/drivers/clocksource/rockchip_timer.c
@@ -0,0 +1,180 @@
1/*
2 * Rockchip timer support
3 *
4 * Copyright (C) Daniel Lezcano <daniel.lezcano@linaro.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/clk.h>
11#include <linux/clockchips.h>
12#include <linux/init.h>
13#include <linux/interrupt.h>
14#include <linux/of.h>
15#include <linux/of_address.h>
16#include <linux/of_irq.h>
17
18#define TIMER_NAME "rk_timer"
19
20#define TIMER_LOAD_COUNT0 0x00
21#define TIMER_LOAD_COUNT1 0x04
22#define TIMER_CONTROL_REG 0x10
23#define TIMER_INT_STATUS 0x18
24
25#define TIMER_DISABLE 0x0
26#define TIMER_ENABLE 0x1
27#define TIMER_MODE_FREE_RUNNING (0 << 1)
28#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
29#define TIMER_INT_UNMASK (1 << 2)
30
31struct bc_timer {
32 struct clock_event_device ce;
33 void __iomem *base;
34 u32 freq;
35};
36
37static struct bc_timer bc_timer;
38
39static inline struct bc_timer *rk_timer(struct clock_event_device *ce)
40{
41 return container_of(ce, struct bc_timer, ce);
42}
43
44static inline void __iomem *rk_base(struct clock_event_device *ce)
45{
46 return rk_timer(ce)->base;
47}
48
49static inline void rk_timer_disable(struct clock_event_device *ce)
50{
51 writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
52 dsb();
53}
54
55static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags)
56{
57 writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
58 rk_base(ce) + TIMER_CONTROL_REG);
59 dsb();
60}
61
62static void rk_timer_update_counter(unsigned long cycles,
63 struct clock_event_device *ce)
64{
65 writel_relaxed(cycles, rk_base(ce) + TIMER_LOAD_COUNT0);
66 writel_relaxed(0, rk_base(ce) + TIMER_LOAD_COUNT1);
67 dsb();
68}
69
70static void rk_timer_interrupt_clear(struct clock_event_device *ce)
71{
72 writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS);
73 dsb();
74}
75
76static inline int rk_timer_set_next_event(unsigned long cycles,
77 struct clock_event_device *ce)
78{
79 rk_timer_disable(ce);
80 rk_timer_update_counter(cycles, ce);
81 rk_timer_enable(ce, TIMER_MODE_USER_DEFINED_COUNT);
82 return 0;
83}
84
85static inline void rk_timer_set_mode(enum clock_event_mode mode,
86 struct clock_event_device *ce)
87{
88 switch (mode) {
89 case CLOCK_EVT_MODE_PERIODIC:
90 rk_timer_disable(ce);
91 rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce);
92 rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING);
93 break;
94 case CLOCK_EVT_MODE_ONESHOT:
95 case CLOCK_EVT_MODE_RESUME:
96 break;
97 case CLOCK_EVT_MODE_UNUSED:
98 case CLOCK_EVT_MODE_SHUTDOWN:
99 rk_timer_disable(ce);
100 break;
101 }
102}
103
104static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
105{
106 struct clock_event_device *ce = dev_id;
107
108 rk_timer_interrupt_clear(ce);
109
110 if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
111 rk_timer_disable(ce);
112
113 ce->event_handler(ce);
114
115 return IRQ_HANDLED;
116}
117
118static void __init rk_timer_init(struct device_node *np)
119{
120 struct clock_event_device *ce = &bc_timer.ce;
121 struct clk *timer_clk;
122 struct clk *pclk;
123 int ret, irq;
124
125 bc_timer.base = of_iomap(np, 0);
126 if (!bc_timer.base) {
127 pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
128 return;
129 }
130
131 pclk = of_clk_get_by_name(np, "pclk");
132 if (IS_ERR(pclk)) {
133 pr_err("Failed to get pclk for '%s'\n", TIMER_NAME);
134 return;
135 }
136
137 if (clk_prepare_enable(pclk)) {
138 pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
139 return;
140 }
141
142 timer_clk = of_clk_get_by_name(np, "timer");
143 if (IS_ERR(timer_clk)) {
144 pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME);
145 return;
146 }
147
148 if (clk_prepare_enable(timer_clk)) {
149 pr_err("Failed to enable timer clock\n");
150 return;
151 }
152
153 bc_timer.freq = clk_get_rate(timer_clk);
154
155 irq = irq_of_parse_and_map(np, 0);
156 if (irq == NO_IRQ) {
157 pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
158 return;
159 }
160
161 ce->name = TIMER_NAME;
162 ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
163 ce->set_next_event = rk_timer_set_next_event;
164 ce->set_mode = rk_timer_set_mode;
165 ce->irq = irq;
166 ce->cpumask = cpumask_of(0);
167 ce->rating = 250;
168
169 rk_timer_interrupt_clear(ce);
170 rk_timer_disable(ce);
171
172 ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
173 if (ret) {
174 pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
175 return;
176 }
177
178 clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);
179}
180CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-atlas7.c
index 361a789d4bee..60f9de3438b0 100644
--- a/drivers/clocksource/timer-marco.c
+++ b/drivers/clocksource/timer-atlas7.c
@@ -38,7 +38,7 @@
38 38
39#define SIRFSOC_TIMER_REG_CNT 6 39#define SIRFSOC_TIMER_REG_CNT 6
40 40
41static unsigned long marco_timer_rate; 41static unsigned long atlas7_timer_rate;
42 42
43static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = { 43static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
44 SIRFSOC_TIMER_WATCHDOG_EN, 44 SIRFSOC_TIMER_WATCHDOG_EN,
@@ -195,7 +195,7 @@ static int sirfsoc_local_timer_setup(struct clock_event_device *ce)
195 ce->rating = 200; 195 ce->rating = 200;
196 ce->set_mode = sirfsoc_timer_set_mode; 196 ce->set_mode = sirfsoc_timer_set_mode;
197 ce->set_next_event = sirfsoc_timer_set_next_event; 197 ce->set_next_event = sirfsoc_timer_set_next_event;
198 clockevents_calc_mult_shift(ce, marco_timer_rate, 60); 198 clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60);
199 ce->max_delta_ns = clockevent_delta2ns(-2, ce); 199 ce->max_delta_ns = clockevent_delta2ns(-2, ce);
200 ce->min_delta_ns = clockevent_delta2ns(2, ce); 200 ce->min_delta_ns = clockevent_delta2ns(2, ce);
201 ce->cpumask = cpumask_of(cpu); 201 ce->cpumask = cpumask_of(cpu);
@@ -255,9 +255,8 @@ static void __init sirfsoc_clockevent_init(void)
255} 255}
256 256
257/* initialize the kernel jiffy timer source */ 257/* initialize the kernel jiffy timer source */
258static void __init sirfsoc_marco_timer_init(struct device_node *np) 258static void __init sirfsoc_atlas7_timer_init(struct device_node *np)
259{ 259{
260 u32 timer_div;
261 struct clk *clk; 260 struct clk *clk;
262 261
263 clk = of_clk_get(np, 0); 262 clk = of_clk_get(np, 0);
@@ -265,7 +264,7 @@ static void __init sirfsoc_marco_timer_init(struct device_node *np)
265 264
266 BUG_ON(clk_prepare_enable(clk)); 265 BUG_ON(clk_prepare_enable(clk));
267 266
268 marco_timer_rate = clk_get_rate(clk); 267 atlas7_timer_rate = clk_get_rate(clk);
269 268
270 /* timer dividers: 0, not divided */ 269 /* timer dividers: 0, not divided */
271 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); 270 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
@@ -283,7 +282,7 @@ static void __init sirfsoc_marco_timer_init(struct device_node *np)
283 /* Clear all interrupts */ 282 /* Clear all interrupts */
284 writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); 283 writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
285 284
286 BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, marco_timer_rate)); 285 BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, atlas7_timer_rate));
287 286
288 sirfsoc_clockevent_init(); 287 sirfsoc_clockevent_init();
289} 288}
@@ -302,6 +301,6 @@ static void __init sirfsoc_of_timer_init(struct device_node *np)
302 if (!sirfsoc_timer1_irq.irq) 301 if (!sirfsoc_timer1_irq.irq)
303 panic("No irq passed for timer1 via DT\n"); 302 panic("No irq passed for timer1 via DT\n");
304 303
305 sirfsoc_marco_timer_init(np); 304 sirfsoc_atlas7_timer_init(np);
306} 305}
307CLOCKSOURCE_OF_DECLARE(sirfsoc_marco_timer, "sirf,marco-tick", sirfsoc_of_timer_init ); 306CLOCKSOURCE_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init);
diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c
new file mode 100644
index 000000000000..7f8388cfa810
--- /dev/null
+++ b/drivers/clocksource/timer-digicolor.c
@@ -0,0 +1,199 @@
1/*
2 * Conexant Digicolor timer driver
3 *
4 * Author: Baruch Siach <baruch@tkos.co.il>
5 *
6 * Copyright (C) 2014 Paradox Innovation Ltd.
7 *
8 * Based on:
9 * Allwinner SoCs hstimer driver
10 *
11 * Copyright (C) 2013 Maxime Ripard
12 *
13 * Maxime Ripard <maxime.ripard@free-electrons.com>
14 *
15 * This file is licensed under the terms of the GNU General Public
16 * License version 2. This program is licensed "as is" without any
17 * warranty of any kind, whether express or implied.
18 */
19
20/*
21 * Conexant Digicolor SoCs have 8 configurable timers, named from "Timer A" to
22 * "Timer H". Timer A is the only one with watchdog support, so it is dedicated
23 * to the watchdog driver. This driver uses Timer B for sched_clock(), and
24 * Timer C for clockevents.
25 */
26
27#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28
29#include <linux/clk.h>
30#include <linux/clockchips.h>
31#include <linux/interrupt.h>
32#include <linux/irq.h>
33#include <linux/irqreturn.h>
34#include <linux/sched_clock.h>
35#include <linux/of.h>
36#include <linux/of_address.h>
37#include <linux/of_irq.h>
38
39enum {
40 TIMER_A,
41 TIMER_B,
42 TIMER_C,
43 TIMER_D,
44 TIMER_E,
45 TIMER_F,
46 TIMER_G,
47 TIMER_H,
48};
49
50#define CONTROL(t) ((t)*8)
51#define COUNT(t) ((t)*8 + 4)
52
53#define CONTROL_DISABLE 0
54#define CONTROL_ENABLE BIT(0)
55#define CONTROL_MODE(m) ((m) << 4)
56#define CONTROL_MODE_ONESHOT CONTROL_MODE(1)
57#define CONTROL_MODE_PERIODIC CONTROL_MODE(2)
58
59struct digicolor_timer {
60 struct clock_event_device ce;
61 void __iomem *base;
62 u32 ticks_per_jiffy;
63 int timer_id; /* one of TIMER_* */
64};
65
66struct digicolor_timer *dc_timer(struct clock_event_device *ce)
67{
68 return container_of(ce, struct digicolor_timer, ce);
69}
70
71static inline void dc_timer_disable(struct clock_event_device *ce)
72{
73 struct digicolor_timer *dt = dc_timer(ce);
74 writeb(CONTROL_DISABLE, dt->base + CONTROL(dt->timer_id));
75}
76
77static inline void dc_timer_enable(struct clock_event_device *ce, u32 mode)
78{
79 struct digicolor_timer *dt = dc_timer(ce);
80 writeb(CONTROL_ENABLE | mode, dt->base + CONTROL(dt->timer_id));
81}
82
83static inline void dc_timer_set_count(struct clock_event_device *ce,
84 unsigned long count)
85{
86 struct digicolor_timer *dt = dc_timer(ce);
87 writel(count, dt->base + COUNT(dt->timer_id));
88}
89
90static void digicolor_clkevt_mode(enum clock_event_mode mode,
91 struct clock_event_device *ce)
92{
93 struct digicolor_timer *dt = dc_timer(ce);
94
95 switch (mode) {
96 case CLOCK_EVT_MODE_PERIODIC:
97 dc_timer_disable(ce);
98 dc_timer_set_count(ce, dt->ticks_per_jiffy);
99 dc_timer_enable(ce, CONTROL_MODE_PERIODIC);
100 break;
101 case CLOCK_EVT_MODE_ONESHOT:
102 dc_timer_disable(ce);
103 dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
104 break;
105 case CLOCK_EVT_MODE_UNUSED:
106 case CLOCK_EVT_MODE_SHUTDOWN:
107 default:
108 dc_timer_disable(ce);
109 break;
110 }
111}
112
113static int digicolor_clkevt_next_event(unsigned long evt,
114 struct clock_event_device *ce)
115{
116 dc_timer_disable(ce);
117 dc_timer_set_count(ce, evt);
118 dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
119
120 return 0;
121}
122
123static struct digicolor_timer dc_timer_dev = {
124 .ce = {
125 .name = "digicolor_tick",
126 .rating = 340,
127 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
128 .set_mode = digicolor_clkevt_mode,
129 .set_next_event = digicolor_clkevt_next_event,
130 },
131 .timer_id = TIMER_C,
132};
133
134static irqreturn_t digicolor_timer_interrupt(int irq, void *dev_id)
135{
136 struct clock_event_device *evt = dev_id;
137
138 evt->event_handler(evt);
139
140 return IRQ_HANDLED;
141}
142
143static u64 digicolor_timer_sched_read(void)
144{
145 return ~readl(dc_timer_dev.base + COUNT(TIMER_B));
146}
147
148static void __init digicolor_timer_init(struct device_node *node)
149{
150 unsigned long rate;
151 struct clk *clk;
152 int ret, irq;
153
154 /*
155 * timer registers are shared with the watchdog timer;
156 * don't map exclusively
157 */
158 dc_timer_dev.base = of_iomap(node, 0);
159 if (!dc_timer_dev.base) {
160 pr_err("Can't map registers");
161 return;
162 }
163
164 irq = irq_of_parse_and_map(node, dc_timer_dev.timer_id);
165 if (irq <= 0) {
166 pr_err("Can't parse IRQ");
167 return;
168 }
169
170 clk = of_clk_get(node, 0);
171 if (IS_ERR(clk)) {
172 pr_err("Can't get timer clock");
173 return;
174 }
175 clk_prepare_enable(clk);
176 rate = clk_get_rate(clk);
177 dc_timer_dev.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
178
179 writeb(CONTROL_DISABLE, dc_timer_dev.base + CONTROL(TIMER_B));
180 writel(UINT_MAX, dc_timer_dev.base + COUNT(TIMER_B));
181 writeb(CONTROL_ENABLE, dc_timer_dev.base + CONTROL(TIMER_B));
182
183 sched_clock_register(digicolor_timer_sched_read, 32, rate);
184 clocksource_mmio_init(dc_timer_dev.base + COUNT(TIMER_B), node->name,
185 rate, 340, 32, clocksource_mmio_readl_down);
186
187 ret = request_irq(irq, digicolor_timer_interrupt,
188 IRQF_TIMER | IRQF_IRQPOLL, "digicolor_timerC",
189 &dc_timer_dev.ce);
190 if (ret)
191 pr_warn("request of timer irq %d failed (%d)\n", irq, ret);
192
193 dc_timer_dev.ce.cpumask = cpu_possible_mask;
194 dc_timer_dev.ce.irq = irq;
195
196 clockevents_config_and_register(&dc_timer_dev.ce, rate, 0, 0xffffffff);
197}
198CLOCKSOURCE_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer",
199 digicolor_timer_init);
diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/versatile.c
index 2798e7492234..0a26d3dde6c0 100644
--- a/drivers/clocksource/versatile.c
+++ b/drivers/clocksource/versatile.c
@@ -36,5 +36,7 @@ static void __init versatile_sched_clock_init(struct device_node *node)
36 36
37 sched_clock_register(versatile_sys_24mhz_read, 32, 24000000); 37 sched_clock_register(versatile_sys_24mhz_read, 32, 24000000);
38} 38}
39CLOCKSOURCE_OF_DECLARE(versatile, "arm,vexpress-sysreg", 39CLOCKSOURCE_OF_DECLARE(vexpress, "arm,vexpress-sysreg",
40 versatile_sched_clock_init);
41CLOCKSOURCE_OF_DECLARE(versatile, "arm,versatile-sysreg",
40 versatile_sched_clock_init); 42 versatile_sched_clock_init);