aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2015-06-02 10:57:47 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-06-02 10:57:47 -0400
commit09cbbf0c169dd81487682622500c81a9012cbeef (patch)
tree0beb190e21c9ba3ad2f2dbc3ee072e1c8623ad27
parentbe3ef76e9d9b97962c70bd6351787d29071ae481 (diff)
parentd4688bdc6335e9faaf3f0173f96932cd520cee1a (diff)
Merge branch 'clockevents/4.2' of http://git.linaro.org/people/daniel.lezcano/linux into timers/core
Pull clockevents/clocksource changes from Daniel Lezcano: - Removed dead code in the files related to mach-msm for qcom (Stephen Boyd) - Cleaned up code for exynos_mct (Krzysztof Kozlowski) - Added the new timer lpc3220 (Joachim Eastwood) - Added the new timer STM32 and ARM system timer (Maxime Coquelin)
-rw-r--r--Documentation/devicetree/bindings/arm/armv7m_systick.txt26
-rw-r--r--Documentation/devicetree/bindings/timer/nxp,lpc3220-timer.txt26
-rw-r--r--Documentation/devicetree/bindings/timer/st,stm32-timer.txt22
-rw-r--r--drivers/clocksource/Kconfig17
-rw-r--r--drivers/clocksource/Makefile3
-rw-r--r--drivers/clocksource/armv7m_systick.c79
-rw-r--r--drivers/clocksource/exynos_mct.c22
-rw-r--r--drivers/clocksource/qcom-timer.c59
-rw-r--r--drivers/clocksource/time-lpc32xx.c272
-rw-r--r--drivers/clocksource/timer-stm32.c184
10 files changed, 632 insertions, 78 deletions
diff --git a/Documentation/devicetree/bindings/arm/armv7m_systick.txt b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
new file mode 100644
index 000000000000..7cf4a24601eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
@@ -0,0 +1,26 @@
1* ARMv7M System Timer
2
3ARMv7-M includes a system timer, known as SysTick. Current driver only
4implements the clocksource feature.
5
6Required properties:
7- compatible : Should be "arm,armv7m-systick"
8- reg : The address range of the timer
9
10Required clocking property, have to be one of:
11- clocks : The input clock of the timer
12- clock-frequency : The rate in HZ in input of the ARM SysTick
13
14Examples:
15
16systick: timer@e000e010 {
17 compatible = "arm,armv7m-systick";
18 reg = <0xe000e010 0x10>;
19 clocks = <&clk_systick>;
20};
21
22systick: timer@e000e010 {
23 compatible = "arm,armv7m-systick";
24 reg = <0xe000e010 0x10>;
25 clock-frequency = <90000000>;
26};
diff --git a/Documentation/devicetree/bindings/timer/nxp,lpc3220-timer.txt b/Documentation/devicetree/bindings/timer/nxp,lpc3220-timer.txt
new file mode 100644
index 000000000000..51b05a0e70d1
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/nxp,lpc3220-timer.txt
@@ -0,0 +1,26 @@
1* NXP LPC3220 timer
2
3The NXP LPC3220 timer is used on a wide range of NXP SoCs. This
4includes LPC32xx, LPC178x, LPC18xx and LPC43xx parts.
5
6Required properties:
7- compatible:
8 Should be "nxp,lpc3220-timer".
9- reg:
10 Address and length of the register set.
11- interrupts:
12 Reference to the timer interrupt
13- clocks:
14 Should contain a reference to timer clock.
15- clock-names:
16 Should contain "timerclk".
17
18Example:
19
20timer1: timer@40085000 {
21 compatible = "nxp,lpc3220-timer";
22 reg = <0x40085000 0x1000>;
23 interrupts = <13>;
24 clocks = <&ccu1 CLK_CPU_TIMER1>;
25 clock-names = "timerclk";
26};
diff --git a/Documentation/devicetree/bindings/timer/st,stm32-timer.txt b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
new file mode 100644
index 000000000000..8ef28e70d6e8
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
@@ -0,0 +1,22 @@
1. STMicroelectronics STM32 timer
2
3The STM32 MCUs family has several general-purpose 16 and 32 bits timers.
4
5Required properties:
6- compatible : Should be "st,stm32-timer"
7- reg : Address and length of the register set
8- clocks : Reference on the timer input clock
9- interrupts : Reference to the timer interrupt
10
11Optional properties:
12- resets: Reference to a reset controller asserting the timer
13
14Example:
15
16timer5: timer@40000c00 {
17 compatible = "st,stm32-timer";
18 reg = <0x40000c00 0x400>;
19 interrupts = <50>;
20 resets = <&rrc 259>;
21 clocks = <&clk_pmtr1>;
22};
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 51d7865fdddb..bec25b39ecf2 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -106,6 +106,16 @@ config CLKSRC_EFM32
106 Support to use the timers of EFM32 SoCs as clock source and clock 106 Support to use the timers of EFM32 SoCs as clock source and clock
107 event device. 107 event device.
108 108
109config CLKSRC_LPC32XX
110 bool
111 select CLKSRC_MMIO
112 select CLKSRC_OF
113
114config CLKSRC_STM32
115 bool "Clocksource for STM32 SoCs" if COMPILE_TEST
116 depends on OF
117 select CLKSRC_MMIO
118
109config ARM_ARCH_TIMER 119config ARM_ARCH_TIMER
110 bool 120 bool
111 select CLKSRC_OF if OF 121 select CLKSRC_OF if OF
@@ -139,6 +149,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
139 help 149 help
140 Use ARM global timer clock source as sched_clock 150 Use ARM global timer clock source as sched_clock
141 151
152config ARMV7M_SYSTICK
153 bool
154 select CLKSRC_OF if OF
155 select CLKSRC_MMIO
156 help
157 This options enables support for the ARMv7M system timer unit
158
142config ATMEL_PIT 159config ATMEL_PIT
143 select CLKSRC_OF if OF 160 select CLKSRC_OF if OF
144 def_bool SOC_AT91SAM9 || SOC_SAMA5 161 def_bool SOC_AT91SAM9 || SOC_SAMA5
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 5b85f6adb258..1831a588b988 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -36,7 +36,9 @@ obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o
36obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_timer.o 36obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_timer.o
37obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o 37obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o
38obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o 38obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o
39obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o
39obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o 40obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o
41obj-$(CONFIG_CLKSRC_LPC32XX) += time-lpc32xx.o
40obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o 42obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o
41obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o 43obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o
42obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o 44obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o
@@ -45,6 +47,7 @@ obj-$(CONFIG_MTK_TIMER) += mtk_timer.o
45 47
46obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o 48obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
47obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o 49obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
50obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o
48obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o 51obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
49obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o 52obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
50obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o 53obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c
new file mode 100644
index 000000000000..addfd2c64f54
--- /dev/null
+++ b/drivers/clocksource/armv7m_systick.c
@@ -0,0 +1,79 @@
1/*
2 * Copyright (C) Maxime Coquelin 2015
3 * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include <linux/kernel.h>
8#include <linux/clocksource.h>
9#include <linux/clockchips.h>
10#include <linux/of.h>
11#include <linux/of_address.h>
12#include <linux/clk.h>
13#include <linux/bitops.h>
14
15#define SYST_CSR 0x00
16#define SYST_RVR 0x04
17#define SYST_CVR 0x08
18#define SYST_CALIB 0x0c
19
20#define SYST_CSR_ENABLE BIT(0)
21
22#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
23
24static void __init system_timer_of_register(struct device_node *np)
25{
26 struct clk *clk = NULL;
27 void __iomem *base;
28 u32 rate;
29 int ret;
30
31 base = of_iomap(np, 0);
32 if (!base) {
33 pr_warn("system-timer: invalid base address\n");
34 return;
35 }
36
37 ret = of_property_read_u32(np, "clock-frequency", &rate);
38 if (ret) {
39 clk = of_clk_get(np, 0);
40 if (IS_ERR(clk))
41 goto out_unmap;
42
43 ret = clk_prepare_enable(clk);
44 if (ret)
45 goto out_clk_put;
46
47 rate = clk_get_rate(clk);
48 if (!rate)
49 goto out_clk_disable;
50 }
51
52 writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
53 writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
54
55 ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
56 200, 24, clocksource_mmio_readl_down);
57 if (ret) {
58 pr_err("failed to init clocksource (%d)\n", ret);
59 if (clk)
60 goto out_clk_disable;
61 else
62 goto out_unmap;
63 }
64
65 pr_info("ARM System timer initialized as clocksource\n");
66
67 return;
68
69out_clk_disable:
70 clk_disable_unprepare(clk);
71out_clk_put:
72 clk_put(clk);
73out_unmap:
74 iounmap(base);
75 pr_warn("ARM System timer register failed (%d)\n", ret);
76}
77
78CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
79 system_timer_of_register);
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index 83564c9cfdbe..935b05936dbd 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -209,7 +209,7 @@ static void exynos4_frc_resume(struct clocksource *cs)
209 exynos4_mct_frc_start(); 209 exynos4_mct_frc_start();
210} 210}
211 211
212struct clocksource mct_frc = { 212static struct clocksource mct_frc = {
213 .name = "mct-frc", 213 .name = "mct-frc",
214 .rating = 400, 214 .rating = 400,
215 .read = exynos4_frc_read, 215 .read = exynos4_frc_read,
@@ -413,7 +413,7 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
413 } 413 }
414} 414}
415 415
416static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) 416static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
417{ 417{
418 struct clock_event_device *evt = &mevt->evt; 418 struct clock_event_device *evt = &mevt->evt;
419 419
@@ -426,12 +426,8 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
426 exynos4_mct_tick_stop(mevt); 426 exynos4_mct_tick_stop(mevt);
427 427
428 /* Clear the MCT tick interrupt */ 428 /* Clear the MCT tick interrupt */
429 if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) { 429 if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1)
430 exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); 430 exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
431 return 1;
432 } else {
433 return 0;
434 }
435} 431}
436 432
437static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) 433static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
@@ -564,18 +560,6 @@ out_irq:
564 free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); 560 free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick);
565} 561}
566 562
567void __init mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1)
568{
569 mct_irqs[MCT_G0_IRQ] = irq_g0;
570 mct_irqs[MCT_L0_IRQ] = irq_l0;
571 mct_irqs[MCT_L1_IRQ] = irq_l1;
572 mct_int_type = MCT_INT_SPI;
573
574 exynos4_timer_resources(NULL, base);
575 exynos4_clocksource_init();
576 exynos4_clockevent_init();
577}
578
579static void __init mct_init_dt(struct device_node *np, unsigned int int_type) 563static void __init mct_init_dt(struct device_node *np, unsigned int int_type)
580{ 564{
581 u32 nr_irqs, i; 565 u32 nr_irqs, i;
diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c
index 098c542e5c53..cba2d015564c 100644
--- a/drivers/clocksource/qcom-timer.c
+++ b/drivers/clocksource/qcom-timer.c
@@ -40,8 +40,6 @@
40 40
41#define GPT_HZ 32768 41#define GPT_HZ 32768
42 42
43#define MSM_DGT_SHIFT 5
44
45static void __iomem *event_base; 43static void __iomem *event_base;
46static void __iomem *sts_base; 44static void __iomem *sts_base;
47 45
@@ -232,7 +230,6 @@ err:
232 register_current_timer_delay(&msm_delay_timer); 230 register_current_timer_delay(&msm_delay_timer);
233} 231}
234 232
235#ifdef CONFIG_ARCH_QCOM
236static void __init msm_dt_timer_init(struct device_node *np) 233static void __init msm_dt_timer_init(struct device_node *np)
237{ 234{
238 u32 freq; 235 u32 freq;
@@ -285,59 +282,3 @@ static void __init msm_dt_timer_init(struct device_node *np)
285} 282}
286CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); 283CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init);
287CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); 284CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init);
288#else
289
290static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source,
291 u32 sts)
292{
293 void __iomem *base;
294
295 base = ioremap(addr, SZ_256);
296 if (!base) {
297 pr_err("Failed to map timer base\n");
298 return -ENOMEM;
299 }
300 event_base = base + event;
301 source_base = base + source;
302 if (sts)
303 sts_base = base + sts;
304
305 return 0;
306}
307
308static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs)
309{
310 /*
311 * Shift timer count down by a constant due to unreliable lower bits
312 * on some targets.
313 */
314 return msm_read_timer_count(cs) >> MSM_DGT_SHIFT;
315}
316
317void __init msm7x01_timer_init(void)
318{
319 struct clocksource *cs = &msm_clocksource;
320
321 if (msm_timer_map(0xc0100000, 0x0, 0x10, 0x0))
322 return;
323 cs->read = msm_read_timer_count_shift;
324 cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT));
325 /* 600 KHz */
326 msm_timer_init(19200000 >> MSM_DGT_SHIFT, 32 - MSM_DGT_SHIFT, 7,
327 false);
328}
329
330void __init msm7x30_timer_init(void)
331{
332 if (msm_timer_map(0xc0100000, 0x4, 0x24, 0x80))
333 return;
334 msm_timer_init(24576000 / 4, 32, 1, false);
335}
336
337void __init qsd8x50_timer_init(void)
338{
339 if (msm_timer_map(0xAC100000, 0x0, 0x10, 0x34))
340 return;
341 msm_timer_init(19200000 / 4, 32, 7, false);
342}
343#endif
diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c
new file mode 100644
index 000000000000..a1c06a2bc77c
--- /dev/null
+++ b/drivers/clocksource/time-lpc32xx.c
@@ -0,0 +1,272 @@
1/*
2 * Clocksource driver for NXP LPC32xx/18xx/43xx timer
3 *
4 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
5 *
6 * Based on:
7 * time-efm32 Copyright (C) 2013 Pengutronix
8 * mach-lpc32xx/timer.c Copyright (C) 2009 - 2010 NXP Semiconductors
9 *
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
13 *
14 */
15
16#define pr_fmt(fmt) "%s: " fmt, __func__
17
18#include <linux/clk.h>
19#include <linux/clockchips.h>
20#include <linux/clocksource.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23#include <linux/kernel.h>
24#include <linux/of.h>
25#include <linux/of_address.h>
26#include <linux/of_irq.h>
27#include <linux/sched_clock.h>
28
29#define LPC32XX_TIMER_IR 0x000
30#define LPC32XX_TIMER_IR_MR0INT BIT(0)
31#define LPC32XX_TIMER_TCR 0x004
32#define LPC32XX_TIMER_TCR_CEN BIT(0)
33#define LPC32XX_TIMER_TCR_CRST BIT(1)
34#define LPC32XX_TIMER_TC 0x008
35#define LPC32XX_TIMER_PR 0x00c
36#define LPC32XX_TIMER_MCR 0x014
37#define LPC32XX_TIMER_MCR_MR0I BIT(0)
38#define LPC32XX_TIMER_MCR_MR0R BIT(1)
39#define LPC32XX_TIMER_MCR_MR0S BIT(2)
40#define LPC32XX_TIMER_MR0 0x018
41#define LPC32XX_TIMER_CTCR 0x070
42
43struct lpc32xx_clock_event_ddata {
44 struct clock_event_device evtdev;
45 void __iomem *base;
46};
47
48/* Needed for the sched clock */
49static void __iomem *clocksource_timer_counter;
50
51static u64 notrace lpc32xx_read_sched_clock(void)
52{
53 return readl(clocksource_timer_counter);
54}
55
56static int lpc32xx_clkevt_next_event(unsigned long delta,
57 struct clock_event_device *evtdev)
58{
59 struct lpc32xx_clock_event_ddata *ddata =
60 container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
61
62 /*
63 * Place timer in reset and program the delta in the prescale
64 * register (PR). When the prescale counter matches the value
65 * in PR the counter register is incremented and the compare
66 * match will trigger. After setup the timer is released from
67 * reset and enabled.
68 */
69 writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
70 writel_relaxed(delta, ddata->base + LPC32XX_TIMER_PR);
71 writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);
72
73 return 0;
74}
75
76static int lpc32xx_clkevt_shutdown(struct clock_event_device *evtdev)
77{
78 struct lpc32xx_clock_event_ddata *ddata =
79 container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
80
81 /* Disable the timer */
82 writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR);
83
84 return 0;
85}
86
87static int lpc32xx_clkevt_oneshot(struct clock_event_device *evtdev)
88{
89 /*
90 * When using oneshot, we must also disable the timer
91 * to wait for the first call to set_next_event().
92 */
93 return lpc32xx_clkevt_shutdown(evtdev);
94}
95
96static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id)
97{
98 struct lpc32xx_clock_event_ddata *ddata = dev_id;
99
100 /* Clear match on channel 0 */
101 writel_relaxed(LPC32XX_TIMER_IR_MR0INT, ddata->base + LPC32XX_TIMER_IR);
102
103 ddata->evtdev.event_handler(&ddata->evtdev);
104
105 return IRQ_HANDLED;
106}
107
108static struct lpc32xx_clock_event_ddata lpc32xx_clk_event_ddata = {
109 .evtdev = {
110 .name = "lpc3220 clockevent",
111 .features = CLOCK_EVT_FEAT_ONESHOT,
112 .rating = 300,
113 .set_next_event = lpc32xx_clkevt_next_event,
114 .set_state_shutdown = lpc32xx_clkevt_shutdown,
115 .set_state_oneshot = lpc32xx_clkevt_oneshot,
116 },
117};
118
119static int __init lpc32xx_clocksource_init(struct device_node *np)
120{
121 void __iomem *base;
122 unsigned long rate;
123 struct clk *clk;
124 int ret;
125
126 clk = of_clk_get_by_name(np, "timerclk");
127 if (IS_ERR(clk)) {
128 pr_err("clock get failed (%lu)\n", PTR_ERR(clk));
129 return PTR_ERR(clk);
130 }
131
132 ret = clk_prepare_enable(clk);
133 if (ret) {
134 pr_err("clock enable failed (%d)\n", ret);
135 goto err_clk_enable;
136 }
137
138 base = of_iomap(np, 0);
139 if (!base) {
140 pr_err("unable to map registers\n");
141 ret = -EADDRNOTAVAIL;
142 goto err_iomap;
143 }
144
145 /*
146 * Disable and reset timer then set it to free running timer
147 * mode (CTCR) with no prescaler (PR) or match operations (MCR).
148 * After setup the timer is released from reset and enabled.
149 */
150 writel_relaxed(LPC32XX_TIMER_TCR_CRST, base + LPC32XX_TIMER_TCR);
151 writel_relaxed(0, base + LPC32XX_TIMER_PR);
152 writel_relaxed(0, base + LPC32XX_TIMER_MCR);
153 writel_relaxed(0, base + LPC32XX_TIMER_CTCR);
154 writel_relaxed(LPC32XX_TIMER_TCR_CEN, base + LPC32XX_TIMER_TCR);
155
156 rate = clk_get_rate(clk);
157 ret = clocksource_mmio_init(base + LPC32XX_TIMER_TC, "lpc3220 timer",
158 rate, 300, 32, clocksource_mmio_readl_up);
159 if (ret) {
160 pr_err("failed to init clocksource (%d)\n", ret);
161 goto err_clocksource_init;
162 }
163
164 clocksource_timer_counter = base + LPC32XX_TIMER_TC;
165 sched_clock_register(lpc32xx_read_sched_clock, 32, rate);
166
167 return 0;
168
169err_clocksource_init:
170 iounmap(base);
171err_iomap:
172 clk_disable_unprepare(clk);
173err_clk_enable:
174 clk_put(clk);
175 return ret;
176}
177
178static int __init lpc32xx_clockevent_init(struct device_node *np)
179{
180 void __iomem *base;
181 unsigned long rate;
182 struct clk *clk;
183 int ret, irq;
184
185 clk = of_clk_get_by_name(np, "timerclk");
186 if (IS_ERR(clk)) {
187 pr_err("clock get failed (%lu)\n", PTR_ERR(clk));
188 return PTR_ERR(clk);
189 }
190
191 ret = clk_prepare_enable(clk);
192 if (ret) {
193 pr_err("clock enable failed (%d)\n", ret);
194 goto err_clk_enable;
195 }
196
197 base = of_iomap(np, 0);
198 if (!base) {
199 pr_err("unable to map registers\n");
200 ret = -EADDRNOTAVAIL;
201 goto err_iomap;
202 }
203
204 irq = irq_of_parse_and_map(np, 0);
205 if (!irq) {
206 pr_err("get irq failed\n");
207 ret = -ENOENT;
208 goto err_irq;
209 }
210
211 /*
212 * Disable timer and clear any pending interrupt (IR) on match
213 * channel 0 (MR0). Configure a compare match value of 1 on MR0
214 * and enable interrupt, reset on match and stop on match (MCR).
215 */
216 writel_relaxed(0, base + LPC32XX_TIMER_TCR);
217 writel_relaxed(0, base + LPC32XX_TIMER_CTCR);
218 writel_relaxed(LPC32XX_TIMER_IR_MR0INT, base + LPC32XX_TIMER_IR);
219 writel_relaxed(1, base + LPC32XX_TIMER_MR0);
220 writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
221 LPC32XX_TIMER_MCR_MR0S, base + LPC32XX_TIMER_MCR);
222
223 rate = clk_get_rate(clk);
224 lpc32xx_clk_event_ddata.base = base;
225 clockevents_config_and_register(&lpc32xx_clk_event_ddata.evtdev,
226 rate, 1, -1);
227
228 ret = request_irq(irq, lpc32xx_clock_event_handler,
229 IRQF_TIMER | IRQF_IRQPOLL, "lpc3220 clockevent",
230 &lpc32xx_clk_event_ddata);
231 if (ret) {
232 pr_err("request irq failed\n");
233 goto err_irq;
234 }
235
236 return 0;
237
238err_irq:
239 iounmap(base);
240err_iomap:
241 clk_disable_unprepare(clk);
242err_clk_enable:
243 clk_put(clk);
244 return ret;
245}
246
247/*
248 * This function asserts that we have exactly one clocksource and one
249 * clock_event_device in the end.
250 */
251static void __init lpc32xx_timer_init(struct device_node *np)
252{
253 static int has_clocksource, has_clockevent;
254 int ret;
255
256 if (!has_clocksource) {
257 ret = lpc32xx_clocksource_init(np);
258 if (!ret) {
259 has_clocksource = 1;
260 return;
261 }
262 }
263
264 if (!has_clockevent) {
265 ret = lpc32xx_clockevent_init(np);
266 if (!ret) {
267 has_clockevent = 1;
268 return;
269 }
270 }
271}
272CLOCKSOURCE_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init);
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
new file mode 100644
index 000000000000..a97e8b50701c
--- /dev/null
+++ b/drivers/clocksource/timer-stm32.c
@@ -0,0 +1,184 @@
1/*
2 * Copyright (C) Maxime Coquelin 2015
3 * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
4 * License terms: GNU General Public License (GPL), version 2
5 *
6 * Inspired by time-efm32.c from Uwe Kleine-Koenig
7 */
8
9#include <linux/kernel.h>
10#include <linux/clocksource.h>
11#include <linux/clockchips.h>
12#include <linux/irq.h>
13#include <linux/interrupt.h>
14#include <linux/of.h>
15#include <linux/of_address.h>
16#include <linux/of_irq.h>
17#include <linux/clk.h>
18#include <linux/reset.h>
19
20#define TIM_CR1 0x00
21#define TIM_DIER 0x0c
22#define TIM_SR 0x10
23#define TIM_EGR 0x14
24#define TIM_PSC 0x28
25#define TIM_ARR 0x2c
26
27#define TIM_CR1_CEN BIT(0)
28#define TIM_CR1_OPM BIT(3)
29#define TIM_CR1_ARPE BIT(7)
30
31#define TIM_DIER_UIE BIT(0)
32
33#define TIM_SR_UIF BIT(0)
34
35#define TIM_EGR_UG BIT(0)
36
37struct stm32_clock_event_ddata {
38 struct clock_event_device evtdev;
39 unsigned periodic_top;
40 void __iomem *base;
41};
42
43static void stm32_clock_event_set_mode(enum clock_event_mode mode,
44 struct clock_event_device *evtdev)
45{
46 struct stm32_clock_event_ddata *data =
47 container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
48 void *base = data->base;
49
50 switch (mode) {
51 case CLOCK_EVT_MODE_PERIODIC:
52 writel_relaxed(data->periodic_top, base + TIM_ARR);
53 writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1);
54 break;
55
56 case CLOCK_EVT_MODE_ONESHOT:
57 default:
58 writel_relaxed(0, base + TIM_CR1);
59 break;
60 }
61}
62
63static int stm32_clock_event_set_next_event(unsigned long evt,
64 struct clock_event_device *evtdev)
65{
66 struct stm32_clock_event_ddata *data =
67 container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
68
69 writel_relaxed(evt, data->base + TIM_ARR);
70 writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
71 data->base + TIM_CR1);
72
73 return 0;
74}
75
76static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
77{
78 struct stm32_clock_event_ddata *data = dev_id;
79
80 writel_relaxed(0, data->base + TIM_SR);
81
82 data->evtdev.event_handler(&data->evtdev);
83
84 return IRQ_HANDLED;
85}
86
87static struct stm32_clock_event_ddata clock_event_ddata = {
88 .evtdev = {
89 .name = "stm32 clockevent",
90 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
91 .set_mode = stm32_clock_event_set_mode,
92 .set_next_event = stm32_clock_event_set_next_event,
93 .rating = 200,
94 },
95};
96
97static void __init stm32_clockevent_init(struct device_node *np)
98{
99 struct stm32_clock_event_ddata *data = &clock_event_ddata;
100 struct clk *clk;
101 struct reset_control *rstc;
102 unsigned long rate, max_delta;
103 int irq, ret, bits, prescaler = 1;
104
105 clk = of_clk_get(np, 0);
106 if (IS_ERR(clk)) {
107 ret = PTR_ERR(clk);
108 pr_err("failed to get clock for clockevent (%d)\n", ret);
109 goto err_clk_get;
110 }
111
112 ret = clk_prepare_enable(clk);
113 if (ret) {
114 pr_err("failed to enable timer clock for clockevent (%d)\n",
115 ret);
116 goto err_clk_enable;
117 }
118
119 rate = clk_get_rate(clk);
120
121 rstc = of_reset_control_get(np, NULL);
122 if (!IS_ERR(rstc)) {
123 reset_control_assert(rstc);
124 reset_control_deassert(rstc);
125 }
126
127 data->base = of_iomap(np, 0);
128 if (!data->base) {
129 pr_err("failed to map registers for clockevent\n");
130 goto err_iomap;
131 }
132
133 irq = irq_of_parse_and_map(np, 0);
134 if (!irq) {
135 pr_err("%s: failed to get irq.\n", np->full_name);
136 goto err_get_irq;
137 }
138
139 /* Detect whether the timer is 16 or 32 bits */
140 writel_relaxed(~0U, data->base + TIM_ARR);
141 max_delta = readl_relaxed(data->base + TIM_ARR);
142 if (max_delta == ~0U) {
143 prescaler = 1;
144 bits = 32;
145 } else {
146 prescaler = 1024;
147 bits = 16;
148 }
149 writel_relaxed(0, data->base + TIM_ARR);
150
151 writel_relaxed(prescaler - 1, data->base + TIM_PSC);
152 writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
153 writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
154 writel_relaxed(0, data->base + TIM_SR);
155
156 data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
157
158 clockevents_config_and_register(&data->evtdev,
159 DIV_ROUND_CLOSEST(rate, prescaler),
160 0x1, max_delta);
161
162 ret = request_irq(irq, stm32_clock_event_handler, IRQF_TIMER,
163 "stm32 clockevent", data);
164 if (ret) {
165 pr_err("%s: failed to request irq.\n", np->full_name);
166 goto err_get_irq;
167 }
168
169 pr_info("%s: STM32 clockevent driver initialized (%d bits)\n",
170 np->full_name, bits);
171
172 return;
173
174err_get_irq:
175 iounmap(data->base);
176err_iomap:
177 clk_disable_unprepare(clk);
178err_clk_enable:
179 clk_put(clk);
180err_clk_get:
181 return;
182}
183
184CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init);