diff options
Diffstat (limited to 'drivers/clocksource')
-rw-r--r-- | drivers/clocksource/Kconfig | 20 | ||||
-rw-r--r-- | drivers/clocksource/Makefile | 2 | ||||
-rw-r--r-- | drivers/clocksource/acpi_pm.c | 23 | ||||
-rw-r--r-- | drivers/clocksource/arm_generic.c | 8 | ||||
-rw-r--r-- | drivers/clocksource/em_sti.c | 8 | ||||
-rw-r--r-- | drivers/clocksource/i8253.c | 2 | ||||
-rw-r--r-- | drivers/clocksource/nomadik-mtu.c | 230 | ||||
-rw-r--r-- | drivers/clocksource/sh_cmt.c | 6 | ||||
-rw-r--r-- | drivers/clocksource/sh_mtu2.c | 6 | ||||
-rw-r--r-- | drivers/clocksource/sh_tmu.c | 6 | ||||
-rw-r--r-- | drivers/clocksource/sunxi_timer.c | 171 | ||||
-rw-r--r-- | drivers/clocksource/time-armada-370-xp.c | 11 |
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 | |||
22 | config ARMADA_370_XP_TIMER | 22 | config ARMADA_370_XP_TIMER |
23 | bool | 23 | bool |
24 | 24 | ||
25 | config SUNXI_TIMER | ||
26 | bool | ||
27 | |||
28 | config 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 | |||
37 | config 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 | |||
25 | config CLKSRC_DBX500_PRCMU | 43 | config 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 | ||
32 | config CLKSRC_DBX500_PRCMU_SCHED_CLOCK | 50 | config 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 | |||
11 | obj-$(CONFIG_CLKSRC_MMIO) += mmio.o | 11 | obj-$(CONFIG_CLKSRC_MMIO) += mmio.o |
12 | obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o | 12 | obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o |
13 | obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o | 13 | obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o |
14 | obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o | ||
14 | obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o | 15 | obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o |
15 | obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o | 16 | obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o |
16 | obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o | 17 | obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o |
18 | obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o | ||
17 | 19 | ||
18 | obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o | 20 | obj-$(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 |
76 | static int __devinitdata acpi_pm_good; | 76 | static int acpi_pm_good; |
77 | static int __init acpi_pm_good_setup(char *__str) | 77 | static 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 | */ |
105 | static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev) | 105 | static 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) | |||
120 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, | 120 | DECLARE_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 | ||
123 | static void __devinit acpi_pm_check_graylist(struct pci_dev *dev) | 123 | static 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 | */ |
234 | static int __init parse_pmtmr(char *arg) | 234 | static 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 | ||
314 | static int __devinit em_sti_probe(struct platform_device *pdev) | 314 | static 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 | ||
382 | static int __devexit em_sti_remove(struct platform_device *pdev) | 382 | static 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 | ||
387 | static const struct of_device_id em_sti_dt_ids[] __devinitconst = { | 387 | static 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 | ||
393 | static struct platform_driver em_sti_device_driver = { | 393 | static 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 | |||
63 | static void __iomem *mtu_base; | ||
64 | static bool clkevt_periodic; | ||
65 | static u32 clk_prescale; | ||
66 | static 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 | */ | ||
74 | static 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 */ | ||
84 | static 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 | |||
96 | void 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 | |||
113 | static 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 | |||
137 | static 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 | */ | ||
148 | static 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 | |||
157 | static 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 | |||
164 | void 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 | |||
177 | void __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 | ||
729 | static int __devinit sh_cmt_probe(struct platform_device *pdev) | 729 | static 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 | ||
770 | static int __devexit sh_cmt_remove(struct platform_device *pdev) | 770 | static 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 | ||
775 | static struct platform_driver sh_cmt_device_driver = { | 775 | static 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 | ||
324 | static int __devinit sh_mtu2_probe(struct platform_device *pdev) | 324 | static 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 | ||
365 | static int __devexit sh_mtu2_remove(struct platform_device *pdev) | 365 | static 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 | ||
370 | static struct platform_driver sh_mtu2_device_driver = { | 370 | static 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 | ||
487 | static int __devinit sh_tmu_probe(struct platform_device *pdev) | 487 | static 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 | ||
528 | static int __devexit sh_tmu_remove(struct platform_device *pdev) | 528 | static 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 | ||
533 | static struct platform_driver sh_tmu_device_driver = { | 533 | static 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 | |||
40 | static void __iomem *timer_base; | ||
41 | |||
42 | static 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 | |||
64 | static 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 | |||
75 | static 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 | |||
85 | static 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 | |||
95 | static 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 | |||
102 | static struct of_device_id sunxi_timer_dt_ids[] = { | ||
103 | { .compatible = "allwinner,sunxi-timer" }, | ||
104 | { } | ||
105 | }; | ||
106 | |||
107 | static 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 | |||
169 | struct 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 |