aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/Kconfig20
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/clocksource/acpi_pm.c23
-rw-r--r--drivers/clocksource/arm_generic.c8
-rw-r--r--drivers/clocksource/em_sti.c8
-rw-r--r--drivers/clocksource/i8253.c2
-rw-r--r--drivers/clocksource/nomadik-mtu.c230
-rw-r--r--drivers/clocksource/sh_cmt.c6
-rw-r--r--drivers/clocksource/sh_mtu2.c6
-rw-r--r--drivers/clocksource/sh_tmu.c6
-rw-r--r--drivers/clocksource/sunxi_timer.c171
-rw-r--r--drivers/clocksource/time-armada-370-xp.c11
12 files changed, 457 insertions, 36 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 6a78073c3808..7fdcbd3f4da5 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -22,6 +22,24 @@ config DW_APB_TIMER_OF
22config ARMADA_370_XP_TIMER 22config ARMADA_370_XP_TIMER
23 bool 23 bool
24 24
25config SUNXI_TIMER
26 bool
27
28config CLKSRC_NOMADIK_MTU
29 bool
30 depends on (ARCH_NOMADIK || ARCH_U8500)
31 select CLKSRC_MMIO
32 help
33 Support for Multi Timer Unit. MTU provides access
34 to multiple interrupt generating programmable
35 32-bit free running decrementing counters.
36
37config CLKSRC_NOMADIK_MTU_SCHED_CLOCK
38 bool
39 depends on CLKSRC_NOMADIK_MTU
40 help
41 Use the Multi Timer Unit as the sched_clock.
42
25config CLKSRC_DBX500_PRCMU 43config CLKSRC_DBX500_PRCMU
26 bool "Clocksource PRCMU Timer" 44 bool "Clocksource PRCMU Timer"
27 depends on UX500_SOC_DB8500 45 depends on UX500_SOC_DB8500
@@ -31,7 +49,7 @@ config CLKSRC_DBX500_PRCMU
31 49
32config CLKSRC_DBX500_PRCMU_SCHED_CLOCK 50config CLKSRC_DBX500_PRCMU_SCHED_CLOCK
33 bool "Clocksource PRCMU Timer sched_clock" 51 bool "Clocksource PRCMU Timer sched_clock"
34 depends on (CLKSRC_DBX500_PRCMU && !NOMADIK_MTU_SCHED_CLOCK) 52 depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK)
35 default y 53 default y
36 help 54 help
37 Use the always on PRCMU Timer as sched_clock 55 Use the always on PRCMU Timer as sched_clock
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 603be366f762..f93453d01673 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -11,8 +11,10 @@ obj-$(CONFIG_CLKBLD_I8253) += i8253.o
11obj-$(CONFIG_CLKSRC_MMIO) += mmio.o 11obj-$(CONFIG_CLKSRC_MMIO) += mmio.o
12obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o 12obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
13obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o 13obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
14obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
14obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o 15obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
15obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o 16obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
16obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o 17obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
18obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o
17 19
18obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o 20obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 6b5cf02c35c8..6efe4d1ab3aa 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -73,7 +73,7 @@ static struct clocksource clocksource_acpi_pm = {
73 73
74 74
75#ifdef CONFIG_PCI 75#ifdef CONFIG_PCI
76static int __devinitdata acpi_pm_good; 76static int acpi_pm_good;
77static int __init acpi_pm_good_setup(char *__str) 77static int __init acpi_pm_good_setup(char *__str)
78{ 78{
79 acpi_pm_good = 1; 79 acpi_pm_good = 1;
@@ -102,7 +102,7 @@ static inline void acpi_pm_need_workaround(void)
102 * incorrect when read). As a result, the ACPI free running count up 102 * incorrect when read). As a result, the ACPI free running count up
103 * timer specification is violated due to erroneous reads. 103 * timer specification is violated due to erroneous reads.
104 */ 104 */
105static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev) 105static void acpi_pm_check_blacklist(struct pci_dev *dev)
106{ 106{
107 if (acpi_pm_good) 107 if (acpi_pm_good)
108 return; 108 return;
@@ -120,7 +120,7 @@ static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev)
120DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, 120DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
121 acpi_pm_check_blacklist); 121 acpi_pm_check_blacklist);
122 122
123static void __devinit acpi_pm_check_graylist(struct pci_dev *dev) 123static void acpi_pm_check_graylist(struct pci_dev *dev)
124{ 124{
125 if (acpi_pm_good) 125 if (acpi_pm_good)
126 return; 126 return;
@@ -233,16 +233,15 @@ fs_initcall(init_acpi_pm_clocksource);
233 */ 233 */
234static int __init parse_pmtmr(char *arg) 234static int __init parse_pmtmr(char *arg)
235{ 235{
236 unsigned long base; 236 unsigned int base;
237 int ret;
237 238
238 if (strict_strtoul(arg, 16, &base)) 239 ret = kstrtouint(arg, 16, &base);
239 return -EINVAL; 240 if (ret)
240#ifdef CONFIG_X86_64 241 return ret;
241 if (base > UINT_MAX) 242
242 return -ERANGE; 243 pr_info("PMTMR IOPort override: 0x%04x -> 0x%04x\n", pmtmr_ioport,
243#endif 244 base);
244 printk(KERN_INFO "PMTMR IOPort override: 0x%04x -> 0x%04lx\n",
245 pmtmr_ioport, base);
246 pmtmr_ioport = base; 245 pmtmr_ioport = base;
247 246
248 return 1; 247 return 1;
diff --git a/drivers/clocksource/arm_generic.c b/drivers/clocksource/arm_generic.c
index c4d9f9566c64..8ae1a61523ff 100644
--- a/drivers/clocksource/arm_generic.c
+++ b/drivers/clocksource/arm_generic.c
@@ -109,7 +109,7 @@ static void __cpuinit arch_timer_setup(struct clock_event_device *clk)
109 109
110 enable_percpu_irq(clk->irq, 0); 110 enable_percpu_irq(clk->irq, 0);
111 111
112 /* Ensure the physical counter is visible to userspace for the vDSO. */ 112 /* Ensure the virtual counter is visible to userspace for the vDSO. */
113 arch_counter_enable_user_access(); 113 arch_counter_enable_user_access();
114} 114}
115 115
@@ -127,7 +127,7 @@ static void __init arch_timer_calibrate(void)
127 127
128 /* Cache the sched_clock multiplier to save a divide in the hot path. */ 128 /* Cache the sched_clock multiplier to save a divide in the hot path. */
129 129
130 sched_clock_mult = NSEC_PER_SEC / arch_timer_rate; 130 sched_clock_mult = DIV_ROUND_CLOSEST(NSEC_PER_SEC, arch_timer_rate);
131 131
132 pr_info("Architected local timer running at %u.%02uMHz.\n", 132 pr_info("Architected local timer running at %u.%02uMHz.\n",
133 arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100); 133 arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100);
@@ -221,10 +221,10 @@ int __init arm_generic_timer_init(void)
221 clocksource_register_hz(&clocksource_counter, arch_timer_rate); 221 clocksource_register_hz(&clocksource_counter, arch_timer_rate);
222 222
223 /* Calibrate the delay loop directly */ 223 /* Calibrate the delay loop directly */
224 lpj_fine = arch_timer_rate / HZ; 224 lpj_fine = DIV_ROUND_CLOSEST(arch_timer_rate, HZ);
225 225
226 /* Immediately configure the timer on the boot CPU */ 226 /* Immediately configure the timer on the boot CPU */
227 arch_timer_setup(per_cpu_ptr(&arch_timer_evt, smp_processor_id())); 227 arch_timer_setup(this_cpu_ptr(&arch_timer_evt));
228 228
229 register_cpu_notifier(&arch_timer_cpu_nb); 229 register_cpu_notifier(&arch_timer_cpu_nb);
230 230
diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c
index 372051d1bba8..e6a553cb73e8 100644
--- a/drivers/clocksource/em_sti.c
+++ b/drivers/clocksource/em_sti.c
@@ -311,7 +311,7 @@ static void em_sti_register_clockevent(struct em_sti_priv *p)
311 clockevents_config_and_register(ced, 1, 2, 0xffffffff); 311 clockevents_config_and_register(ced, 1, 2, 0xffffffff);
312} 312}
313 313
314static int __devinit em_sti_probe(struct platform_device *pdev) 314static int em_sti_probe(struct platform_device *pdev)
315{ 315{
316 struct em_sti_priv *p; 316 struct em_sti_priv *p;
317 struct resource *res; 317 struct resource *res;
@@ -379,12 +379,12 @@ err0:
379 return ret; 379 return ret;
380} 380}
381 381
382static int __devexit em_sti_remove(struct platform_device *pdev) 382static int em_sti_remove(struct platform_device *pdev)
383{ 383{
384 return -EBUSY; /* cannot unregister clockevent and clocksource */ 384 return -EBUSY; /* cannot unregister clockevent and clocksource */
385} 385}
386 386
387static const struct of_device_id em_sti_dt_ids[] __devinitconst = { 387static const struct of_device_id em_sti_dt_ids[] = {
388 { .compatible = "renesas,em-sti", }, 388 { .compatible = "renesas,em-sti", },
389 {}, 389 {},
390}; 390};
@@ -392,7 +392,7 @@ MODULE_DEVICE_TABLE(of, em_sti_dt_ids);
392 392
393static struct platform_driver em_sti_device_driver = { 393static struct platform_driver em_sti_device_driver = {
394 .probe = em_sti_probe, 394 .probe = em_sti_probe,
395 .remove = __devexit_p(em_sti_remove), 395 .remove = em_sti_remove,
396 .driver = { 396 .driver = {
397 .name = "em_sti", 397 .name = "em_sti",
398 .of_match_table = em_sti_dt_ids, 398 .of_match_table = em_sti_dt_ids,
diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c
index e7cab2da910f..14ee3efcc404 100644
--- a/drivers/clocksource/i8253.c
+++ b/drivers/clocksource/i8253.c
@@ -35,7 +35,7 @@ static cycle_t i8253_read(struct clocksource *cs)
35 35
36 raw_spin_lock_irqsave(&i8253_lock, flags); 36 raw_spin_lock_irqsave(&i8253_lock, flags);
37 /* 37 /*
38 * Although our caller may have the read side of xtime_lock, 38 * Although our caller may have the read side of jiffies_lock,
39 * this is now a seqlock, and we are cheating in this routine 39 * this is now a seqlock, and we are cheating in this routine
40 * by having side effects on state that we cannot undo if 40 * by having side effects on state that we cannot undo if
41 * there is a collision on the seqlock and our caller has to 41 * there is a collision on the seqlock and our caller has to
diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c
new file mode 100644
index 000000000000..8914c3c1c88b
--- /dev/null
+++ b/drivers/clocksource/nomadik-mtu.c
@@ -0,0 +1,230 @@
1/*
2 * Copyright (C) 2008 STMicroelectronics
3 * Copyright (C) 2010 Alessandro Rubini
4 * Copyright (C) 2010 Linus Walleij for ST-Ericsson
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/init.h>
11#include <linux/interrupt.h>
12#include <linux/irq.h>
13#include <linux/io.h>
14#include <linux/clockchips.h>
15#include <linux/clocksource.h>
16#include <linux/clk.h>
17#include <linux/jiffies.h>
18#include <linux/err.h>
19#include <linux/platform_data/clocksource-nomadik-mtu.h>
20#include <asm/mach/time.h>
21#include <asm/sched_clock.h>
22
23/*
24 * The MTU device hosts four different counters, with 4 set of
25 * registers. These are register names.
26 */
27
28#define MTU_IMSC 0x00 /* Interrupt mask set/clear */
29#define MTU_RIS 0x04 /* Raw interrupt status */
30#define MTU_MIS 0x08 /* Masked interrupt status */
31#define MTU_ICR 0x0C /* Interrupt clear register */
32
33/* per-timer registers take 0..3 as argument */
34#define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */
35#define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */
36#define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */
37#define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */
38
39/* bits for the control register */
40#define MTU_CRn_ENA 0x80
41#define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */
42#define MTU_CRn_PRESCALE_MASK 0x0c
43#define MTU_CRn_PRESCALE_1 0x00
44#define MTU_CRn_PRESCALE_16 0x04
45#define MTU_CRn_PRESCALE_256 0x08
46#define MTU_CRn_32BITS 0x02
47#define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/
48
49/* Other registers are usual amba/primecell registers, currently not used */
50#define MTU_ITCR 0xff0
51#define MTU_ITOP 0xff4
52
53#define MTU_PERIPH_ID0 0xfe0
54#define MTU_PERIPH_ID1 0xfe4
55#define MTU_PERIPH_ID2 0xfe8
56#define MTU_PERIPH_ID3 0xfeC
57
58#define MTU_PCELL0 0xff0
59#define MTU_PCELL1 0xff4
60#define MTU_PCELL2 0xff8
61#define MTU_PCELL3 0xffC
62
63static void __iomem *mtu_base;
64static bool clkevt_periodic;
65static u32 clk_prescale;
66static u32 nmdk_cycle; /* write-once */
67
68#ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
69/*
70 * Override the global weak sched_clock symbol with this
71 * local implementation which uses the clocksource to get some
72 * better resolution when scheduling the kernel.
73 */
74static u32 notrace nomadik_read_sched_clock(void)
75{
76 if (unlikely(!mtu_base))
77 return 0;
78
79 return -readl(mtu_base + MTU_VAL(0));
80}
81#endif
82
83/* Clockevent device: use one-shot mode */
84static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev)
85{
86 writel(1 << 1, mtu_base + MTU_IMSC);
87 writel(evt, mtu_base + MTU_LR(1));
88 /* Load highest value, enable device, enable interrupts */
89 writel(MTU_CRn_ONESHOT | clk_prescale |
90 MTU_CRn_32BITS | MTU_CRn_ENA,
91 mtu_base + MTU_CR(1));
92
93 return 0;
94}
95
96void nmdk_clkevt_reset(void)
97{
98 if (clkevt_periodic) {
99 /* Timer: configure load and background-load, and fire it up */
100 writel(nmdk_cycle, mtu_base + MTU_LR(1));
101 writel(nmdk_cycle, mtu_base + MTU_BGLR(1));
102
103 writel(MTU_CRn_PERIODIC | clk_prescale |
104 MTU_CRn_32BITS | MTU_CRn_ENA,
105 mtu_base + MTU_CR(1));
106 writel(1 << 1, mtu_base + MTU_IMSC);
107 } else {
108 /* Generate an interrupt to start the clockevent again */
109 (void) nmdk_clkevt_next(nmdk_cycle, NULL);
110 }
111}
112
113static void nmdk_clkevt_mode(enum clock_event_mode mode,
114 struct clock_event_device *dev)
115{
116 switch (mode) {
117 case CLOCK_EVT_MODE_PERIODIC:
118 clkevt_periodic = true;
119 nmdk_clkevt_reset();
120 break;
121 case CLOCK_EVT_MODE_ONESHOT:
122 clkevt_periodic = false;
123 break;
124 case CLOCK_EVT_MODE_SHUTDOWN:
125 case CLOCK_EVT_MODE_UNUSED:
126 writel(0, mtu_base + MTU_IMSC);
127 /* disable timer */
128 writel(0, mtu_base + MTU_CR(1));
129 /* load some high default value */
130 writel(0xffffffff, mtu_base + MTU_LR(1));
131 break;
132 case CLOCK_EVT_MODE_RESUME:
133 break;
134 }
135}
136
137static struct clock_event_device nmdk_clkevt = {
138 .name = "mtu_1",
139 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
140 .rating = 200,
141 .set_mode = nmdk_clkevt_mode,
142 .set_next_event = nmdk_clkevt_next,
143};
144
145/*
146 * IRQ Handler for timer 1 of the MTU block.
147 */
148static irqreturn_t nmdk_timer_interrupt(int irq, void *dev_id)
149{
150 struct clock_event_device *evdev = dev_id;
151
152 writel(1 << 1, mtu_base + MTU_ICR); /* Interrupt clear reg */
153 evdev->event_handler(evdev);
154 return IRQ_HANDLED;
155}
156
157static struct irqaction nmdk_timer_irq = {
158 .name = "Nomadik Timer Tick",
159 .flags = IRQF_DISABLED | IRQF_TIMER,
160 .handler = nmdk_timer_interrupt,
161 .dev_id = &nmdk_clkevt,
162};
163
164void nmdk_clksrc_reset(void)
165{
166 /* Disable */
167 writel(0, mtu_base + MTU_CR(0));
168
169 /* ClockSource: configure load and background-load, and fire it up */
170 writel(nmdk_cycle, mtu_base + MTU_LR(0));
171 writel(nmdk_cycle, mtu_base + MTU_BGLR(0));
172
173 writel(clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA,
174 mtu_base + MTU_CR(0));
175}
176
177void __init nmdk_timer_init(void __iomem *base, int irq)
178{
179 unsigned long rate;
180 struct clk *clk0, *pclk0;
181
182 mtu_base = base;
183
184 pclk0 = clk_get_sys("mtu0", "apb_pclk");
185 BUG_ON(IS_ERR(pclk0));
186 BUG_ON(clk_prepare(pclk0) < 0);
187 BUG_ON(clk_enable(pclk0) < 0);
188
189 clk0 = clk_get_sys("mtu0", NULL);
190 BUG_ON(IS_ERR(clk0));
191 BUG_ON(clk_prepare(clk0) < 0);
192 BUG_ON(clk_enable(clk0) < 0);
193
194 /*
195 * Tick rate is 2.4MHz for Nomadik and 2.4Mhz, 100MHz or 133 MHz
196 * for ux500.
197 * Use a divide-by-16 counter if the tick rate is more than 32MHz.
198 * At 32 MHz, the timer (with 32 bit counter) can be programmed
199 * to wake-up at a max 127s a head in time. Dividing a 2.4 MHz timer
200 * with 16 gives too low timer resolution.
201 */
202 rate = clk_get_rate(clk0);
203 if (rate > 32000000) {
204 rate /= 16;
205 clk_prescale = MTU_CRn_PRESCALE_16;
206 } else {
207 clk_prescale = MTU_CRn_PRESCALE_1;
208 }
209
210 /* Cycles for periodic mode */
211 nmdk_cycle = DIV_ROUND_CLOSEST(rate, HZ);
212
213
214 /* Timer 0 is the free running clocksource */
215 nmdk_clksrc_reset();
216
217 if (clocksource_mmio_init(mtu_base + MTU_VAL(0), "mtu_0",
218 rate, 200, 32, clocksource_mmio_readl_down))
219 pr_err("timer: failed to initialize clock source %s\n",
220 "mtu_0");
221
222#ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
223 setup_sched_clock(nomadik_read_sched_clock, 32, rate);
224#endif
225
226 /* Timer 1 is used for events, register irq and clockevents */
227 setup_irq(irq, &nmdk_timer_irq);
228 nmdk_clkevt.cpumask = cpumask_of(0);
229 clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU);
230}
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index a5f7829f2799..488c14cc8dbf 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -726,7 +726,7 @@ err0:
726 return ret; 726 return ret;
727} 727}
728 728
729static int __devinit sh_cmt_probe(struct platform_device *pdev) 729static int sh_cmt_probe(struct platform_device *pdev)
730{ 730{
731 struct sh_cmt_priv *p = platform_get_drvdata(pdev); 731 struct sh_cmt_priv *p = platform_get_drvdata(pdev);
732 struct sh_timer_config *cfg = pdev->dev.platform_data; 732 struct sh_timer_config *cfg = pdev->dev.platform_data;
@@ -767,14 +767,14 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
767 return 0; 767 return 0;
768} 768}
769 769
770static int __devexit sh_cmt_remove(struct platform_device *pdev) 770static int sh_cmt_remove(struct platform_device *pdev)
771{ 771{
772 return -EBUSY; /* cannot unregister clockevent and clocksource */ 772 return -EBUSY; /* cannot unregister clockevent and clocksource */
773} 773}
774 774
775static struct platform_driver sh_cmt_device_driver = { 775static struct platform_driver sh_cmt_device_driver = {
776 .probe = sh_cmt_probe, 776 .probe = sh_cmt_probe,
777 .remove = __devexit_p(sh_cmt_remove), 777 .remove = sh_cmt_remove,
778 .driver = { 778 .driver = {
779 .name = "sh_cmt", 779 .name = "sh_cmt",
780 } 780 }
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
index c5eea858054a..83943e27cfac 100644
--- a/drivers/clocksource/sh_mtu2.c
+++ b/drivers/clocksource/sh_mtu2.c
@@ -321,7 +321,7 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
321 return ret; 321 return ret;
322} 322}
323 323
324static int __devinit sh_mtu2_probe(struct platform_device *pdev) 324static int sh_mtu2_probe(struct platform_device *pdev)
325{ 325{
326 struct sh_mtu2_priv *p = platform_get_drvdata(pdev); 326 struct sh_mtu2_priv *p = platform_get_drvdata(pdev);
327 struct sh_timer_config *cfg = pdev->dev.platform_data; 327 struct sh_timer_config *cfg = pdev->dev.platform_data;
@@ -362,14 +362,14 @@ static int __devinit sh_mtu2_probe(struct platform_device *pdev)
362 return 0; 362 return 0;
363} 363}
364 364
365static int __devexit sh_mtu2_remove(struct platform_device *pdev) 365static int sh_mtu2_remove(struct platform_device *pdev)
366{ 366{
367 return -EBUSY; /* cannot unregister clockevent */ 367 return -EBUSY; /* cannot unregister clockevent */
368} 368}
369 369
370static struct platform_driver sh_mtu2_device_driver = { 370static struct platform_driver sh_mtu2_device_driver = {
371 .probe = sh_mtu2_probe, 371 .probe = sh_mtu2_probe,
372 .remove = __devexit_p(sh_mtu2_remove), 372 .remove = sh_mtu2_remove,
373 .driver = { 373 .driver = {
374 .name = "sh_mtu2", 374 .name = "sh_mtu2",
375 } 375 }
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index 0cc4add88279..b4502edce2a1 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -484,7 +484,7 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
484 return ret; 484 return ret;
485} 485}
486 486
487static int __devinit sh_tmu_probe(struct platform_device *pdev) 487static int sh_tmu_probe(struct platform_device *pdev)
488{ 488{
489 struct sh_tmu_priv *p = platform_get_drvdata(pdev); 489 struct sh_tmu_priv *p = platform_get_drvdata(pdev);
490 struct sh_timer_config *cfg = pdev->dev.platform_data; 490 struct sh_timer_config *cfg = pdev->dev.platform_data;
@@ -525,14 +525,14 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
525 return 0; 525 return 0;
526} 526}
527 527
528static int __devexit sh_tmu_remove(struct platform_device *pdev) 528static int sh_tmu_remove(struct platform_device *pdev)
529{ 529{
530 return -EBUSY; /* cannot unregister clockevent and clocksource */ 530 return -EBUSY; /* cannot unregister clockevent and clocksource */
531} 531}
532 532
533static struct platform_driver sh_tmu_device_driver = { 533static struct platform_driver sh_tmu_device_driver = {
534 .probe = sh_tmu_probe, 534 .probe = sh_tmu_probe,
535 .remove = __devexit_p(sh_tmu_remove), 535 .remove = sh_tmu_remove,
536 .driver = { 536 .driver = {
537 .name = "sh_tmu", 537 .name = "sh_tmu",
538 } 538 }
diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sunxi_timer.c
new file mode 100644
index 000000000000..3cd1bd3d7aee
--- /dev/null
+++ b/drivers/clocksource/sunxi_timer.c
@@ -0,0 +1,171 @@
1/*
2 * Allwinner A1X SoCs timer handling.
3 *
4 * Copyright (C) 2012 Maxime Ripard
5 *
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
7 *
8 * Based on code from
9 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
10 * Benn Huang <benn@allwinnertech.com>
11 *
12 * This file is licensed under the terms of the GNU General Public
13 * License version 2. This program is licensed "as is" without any
14 * warranty of any kind, whether express or implied.
15 */
16
17#include <linux/clk.h>
18#include <linux/clockchips.h>
19#include <linux/interrupt.h>
20#include <linux/irq.h>
21#include <linux/irqreturn.h>
22#include <linux/of.h>
23#include <linux/of_address.h>
24#include <linux/of_irq.h>
25#include <linux/sunxi_timer.h>
26#include <linux/clk/sunxi.h>
27
28#define TIMER_CTL_REG 0x00
29#define TIMER_CTL_ENABLE (1 << 0)
30#define TIMER_IRQ_ST_REG 0x04
31#define TIMER0_CTL_REG 0x10
32#define TIMER0_CTL_ENABLE (1 << 0)
33#define TIMER0_CTL_AUTORELOAD (1 << 1)
34#define TIMER0_CTL_ONESHOT (1 << 7)
35#define TIMER0_INTVAL_REG 0x14
36#define TIMER0_CNTVAL_REG 0x18
37
38#define TIMER_SCAL 16
39
40static void __iomem *timer_base;
41
42static void sunxi_clkevt_mode(enum clock_event_mode mode,
43 struct clock_event_device *clk)
44{
45 u32 u = readl(timer_base + TIMER0_CTL_REG);
46
47 switch (mode) {
48 case CLOCK_EVT_MODE_PERIODIC:
49 u &= ~(TIMER0_CTL_ONESHOT);
50 writel(u | TIMER0_CTL_ENABLE, timer_base + TIMER0_CTL_REG);
51 break;
52
53 case CLOCK_EVT_MODE_ONESHOT:
54 writel(u | TIMER0_CTL_ONESHOT, timer_base + TIMER0_CTL_REG);
55 break;
56 case CLOCK_EVT_MODE_UNUSED:
57 case CLOCK_EVT_MODE_SHUTDOWN:
58 default:
59 writel(u & ~(TIMER0_CTL_ENABLE), timer_base + TIMER0_CTL_REG);
60 break;
61 }
62}
63
64static int sunxi_clkevt_next_event(unsigned long evt,
65 struct clock_event_device *unused)
66{
67 u32 u = readl(timer_base + TIMER0_CTL_REG);
68 writel(evt, timer_base + TIMER0_CNTVAL_REG);
69 writel(u | TIMER0_CTL_ENABLE | TIMER0_CTL_AUTORELOAD,
70 timer_base + TIMER0_CTL_REG);
71
72 return 0;
73}
74
75static struct clock_event_device sunxi_clockevent = {
76 .name = "sunxi_tick",
77 .shift = 32,
78 .rating = 300,
79 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
80 .set_mode = sunxi_clkevt_mode,
81 .set_next_event = sunxi_clkevt_next_event,
82};
83
84
85static irqreturn_t sunxi_timer_interrupt(int irq, void *dev_id)
86{
87 struct clock_event_device *evt = (struct clock_event_device *)dev_id;
88
89 writel(0x1, timer_base + TIMER_IRQ_ST_REG);
90 evt->event_handler(evt);
91
92 return IRQ_HANDLED;
93}
94
95static struct irqaction sunxi_timer_irq = {
96 .name = "sunxi_timer0",
97 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
98 .handler = sunxi_timer_interrupt,
99 .dev_id = &sunxi_clockevent,
100};
101
102static struct of_device_id sunxi_timer_dt_ids[] = {
103 { .compatible = "allwinner,sunxi-timer" },
104 { }
105};
106
107static void __init sunxi_timer_init(void)
108{
109 struct device_node *node;
110 unsigned long rate = 0;
111 struct clk *clk;
112 int ret, irq;
113 u32 val;
114
115 node = of_find_matching_node(NULL, sunxi_timer_dt_ids);
116 if (!node)
117 panic("No sunxi timer node");
118
119 timer_base = of_iomap(node, 0);
120 if (!timer_base)
121 panic("Can't map registers");
122
123 irq = irq_of_parse_and_map(node, 0);
124 if (irq <= 0)
125 panic("Can't parse IRQ");
126
127 sunxi_init_clocks();
128
129 clk = of_clk_get(node, 0);
130 if (IS_ERR(clk))
131 panic("Can't get timer clock");
132
133 rate = clk_get_rate(clk);
134
135 writel(rate / (TIMER_SCAL * HZ),
136 timer_base + TIMER0_INTVAL_REG);
137
138 /* set clock source to HOSC, 16 pre-division */
139 val = readl(timer_base + TIMER0_CTL_REG);
140 val &= ~(0x07 << 4);
141 val &= ~(0x03 << 2);
142 val |= (4 << 4) | (1 << 2);
143 writel(val, timer_base + TIMER0_CTL_REG);
144
145 /* set mode to auto reload */
146 val = readl(timer_base + TIMER0_CTL_REG);
147 writel(val | TIMER0_CTL_AUTORELOAD, timer_base + TIMER0_CTL_REG);
148
149 ret = setup_irq(irq, &sunxi_timer_irq);
150 if (ret)
151 pr_warn("failed to setup irq %d\n", irq);
152
153 /* Enable timer0 interrupt */
154 val = readl(timer_base + TIMER_CTL_REG);
155 writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG);
156
157 sunxi_clockevent.mult = div_sc(rate / TIMER_SCAL,
158 NSEC_PER_SEC,
159 sunxi_clockevent.shift);
160 sunxi_clockevent.max_delta_ns = clockevent_delta2ns(0xff,
161 &sunxi_clockevent);
162 sunxi_clockevent.min_delta_ns = clockevent_delta2ns(0x1,
163 &sunxi_clockevent);
164 sunxi_clockevent.cpumask = cpumask_of(0);
165
166 clockevents_register_device(&sunxi_clockevent);
167}
168
169struct sys_timer sunxi_timer = {
170 .init = sunxi_timer_init,
171};
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index 4674f94957cd..a4605fd7e303 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -18,6 +18,7 @@
18#include <linux/init.h> 18#include <linux/init.h>
19#include <linux/platform_device.h> 19#include <linux/platform_device.h>
20#include <linux/kernel.h> 20#include <linux/kernel.h>
21#include <linux/clk.h>
21#include <linux/timer.h> 22#include <linux/timer.h>
22#include <linux/clockchips.h> 23#include <linux/clockchips.h>
23#include <linux/interrupt.h> 24#include <linux/interrupt.h>
@@ -167,7 +168,6 @@ void __init armada_370_xp_timer_init(void)
167 u32 u; 168 u32 u;
168 struct device_node *np; 169 struct device_node *np;
169 unsigned int timer_clk; 170 unsigned int timer_clk;
170 int ret;
171 np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer"); 171 np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
172 timer_base = of_iomap(np, 0); 172 timer_base = of_iomap(np, 0);
173 WARN_ON(!timer_base); 173 WARN_ON(!timer_base);
@@ -179,13 +179,14 @@ void __init armada_370_xp_timer_init(void)
179 timer_base + TIMER_CTRL_OFF); 179 timer_base + TIMER_CTRL_OFF);
180 timer_clk = 25000000; 180 timer_clk = 25000000;
181 } else { 181 } else {
182 u32 clk = 0; 182 unsigned long rate = 0;
183 ret = of_property_read_u32(np, "clock-frequency", &clk); 183 struct clk *clk = of_clk_get(np, 0);
184 WARN_ON(!clk || ret < 0); 184 WARN_ON(IS_ERR(clk));
185 rate = clk_get_rate(clk);
185 u = readl(timer_base + TIMER_CTRL_OFF); 186 u = readl(timer_base + TIMER_CTRL_OFF);
186 writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ), 187 writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ),
187 timer_base + TIMER_CTRL_OFF); 188 timer_base + TIMER_CTRL_OFF);
188 timer_clk = clk / TIMER_DIVIDER; 189 timer_clk = rate / TIMER_DIVIDER;
189 } 190 }
190 191
191 /* We use timer 0 as clocksource, and timer 1 for 192 /* We use timer 0 as clocksource, and timer 1 for