diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2013-04-08 12:34:19 -0400 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2013-04-08 12:34:19 -0400 |
| commit | 6b5606e0834bb173a8ce3505edec078f135e9f6c (patch) | |
| tree | 9f3bdc09be01e14fb68368b1c111a04cc570518f /drivers/clocksource | |
| parent | e9069cf8b74b50d804fd540a9fd1383504f4af93 (diff) | |
| parent | 4f0f234fce1d263cc9881456352e8fd56ead0514 (diff) | |
Merge branch 'zynq/clksrc/cleanup' of git://git.xilinx.com/linux-xlnx into next/drivers
From Michal Simek <michal.simek@xilinx.com>:
* 'zynq/clksrc/cleanup' of git://git.xilinx.com/linux-xlnx:
arm: zynq: Move timer to generic location
arm: zynq: Do not use xilinx specific function names
arm: zynq: Move timer to clocksource interface
arm: zynq: Use standard timer binding
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/clocksource')
| -rw-r--r-- | drivers/clocksource/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/clocksource/Makefile | 1 | ||||
| -rw-r--r-- | drivers/clocksource/bcm2835_timer.c | 12 | ||||
| -rw-r--r-- | drivers/clocksource/cadence_ttc_timer.c | 436 | ||||
| -rw-r--r-- | drivers/clocksource/clksrc-of.c | 5 | ||||
| -rw-r--r-- | drivers/clocksource/tegra20_timer.c | 73 | ||||
| -rw-r--r-- | drivers/clocksource/vt8500_timer.c | 16 |
7 files changed, 473 insertions, 73 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index e507ab7df60b..3167fda9bbb3 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
| @@ -31,6 +31,9 @@ config SUNXI_TIMER | |||
| 31 | config VT8500_TIMER | 31 | config VT8500_TIMER |
| 32 | bool | 32 | bool |
| 33 | 33 | ||
| 34 | config CADENCE_TTC_TIMER | ||
| 35 | bool | ||
| 36 | |||
| 34 | config CLKSRC_NOMADIK_MTU | 37 | config CLKSRC_NOMADIK_MTU |
| 35 | bool | 38 | bool |
| 36 | depends on (ARCH_NOMADIK || ARCH_U8500) | 39 | depends on (ARCH_NOMADIK || ARCH_U8500) |
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 4d8283aec5b5..e74c8ce26bf0 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
| @@ -19,6 +19,7 @@ obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o | |||
| 19 | obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o | 19 | obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o |
| 20 | obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o | 20 | obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o |
| 21 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o | 21 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o |
| 22 | obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o | ||
| 22 | 23 | ||
| 23 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o | 24 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o |
| 24 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o | 25 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o |
diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 50c68fef944b..766611d29945 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c | |||
| @@ -95,23 +95,13 @@ static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id) | |||
| 95 | } | 95 | } |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | static struct of_device_id bcm2835_time_match[] __initconst = { | 98 | static void __init bcm2835_timer_init(struct device_node *node) |
| 99 | { .compatible = "brcm,bcm2835-system-timer" }, | ||
| 100 | {} | ||
| 101 | }; | ||
| 102 | |||
| 103 | static void __init bcm2835_timer_init(void) | ||
| 104 | { | 99 | { |
| 105 | struct device_node *node; | ||
| 106 | void __iomem *base; | 100 | void __iomem *base; |
| 107 | u32 freq; | 101 | u32 freq; |
| 108 | int irq; | 102 | int irq; |
| 109 | struct bcm2835_timer *timer; | 103 | struct bcm2835_timer *timer; |
| 110 | 104 | ||
| 111 | node = of_find_matching_node(NULL, bcm2835_time_match); | ||
| 112 | if (!node) | ||
| 113 | panic("No bcm2835 timer node"); | ||
| 114 | |||
| 115 | base = of_iomap(node, 0); | 105 | base = of_iomap(node, 0); |
| 116 | if (!base) | 106 | if (!base) |
| 117 | panic("Can't remap registers"); | 107 | panic("Can't remap registers"); |
diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c new file mode 100644 index 000000000000..685bc60e210a --- /dev/null +++ b/drivers/clocksource/cadence_ttc_timer.c | |||
| @@ -0,0 +1,436 @@ | |||
| 1 | /* | ||
| 2 | * This file contains driver for the Cadence Triple Timer Counter Rev 06 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011-2013 Xilinx | ||
| 5 | * | ||
| 6 | * based on arch/mips/kernel/time.c timer driver | ||
| 7 | * | ||
| 8 | * This software is licensed under the terms of the GNU General Public | ||
| 9 | * License version 2, as published by the Free Software Foundation, and | ||
| 10 | * may be copied, distributed, and modified under those terms. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/clk.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/clockchips.h> | ||
| 21 | #include <linux/of_address.h> | ||
| 22 | #include <linux/of_irq.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/clk-provider.h> | ||
| 25 | |||
| 26 | /* | ||
| 27 | * This driver configures the 2 16-bit count-up timers as follows: | ||
| 28 | * | ||
| 29 | * T1: Timer 1, clocksource for generic timekeeping | ||
| 30 | * T2: Timer 2, clockevent source for hrtimers | ||
| 31 | * T3: Timer 3, <unused> | ||
| 32 | * | ||
| 33 | * The input frequency to the timer module for emulation is 2.5MHz which is | ||
| 34 | * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32, | ||
| 35 | * the timers are clocked at 78.125KHz (12.8 us resolution). | ||
| 36 | |||
| 37 | * The input frequency to the timer module in silicon is configurable and | ||
| 38 | * obtained from device tree. The pre-scaler of 32 is used. | ||
| 39 | */ | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Timer Register Offset Definitions of Timer 1, Increment base address by 4 | ||
| 43 | * and use same offsets for Timer 2 | ||
| 44 | */ | ||
| 45 | #define TTC_CLK_CNTRL_OFFSET 0x00 /* Clock Control Reg, RW */ | ||
| 46 | #define TTC_CNT_CNTRL_OFFSET 0x0C /* Counter Control Reg, RW */ | ||
| 47 | #define TTC_COUNT_VAL_OFFSET 0x18 /* Counter Value Reg, RO */ | ||
| 48 | #define TTC_INTR_VAL_OFFSET 0x24 /* Interval Count Reg, RW */ | ||
| 49 | #define TTC_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */ | ||
| 50 | #define TTC_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */ | ||
| 51 | |||
| 52 | #define TTC_CNT_CNTRL_DISABLE_MASK 0x1 | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Setup the timers to use pre-scaling, using a fixed value for now that will | ||
| 56 | * work across most input frequency, but it may need to be more dynamic | ||
| 57 | */ | ||
| 58 | #define PRESCALE_EXPONENT 11 /* 2 ^ PRESCALE_EXPONENT = PRESCALE */ | ||
| 59 | #define PRESCALE 2048 /* The exponent must match this */ | ||
| 60 | #define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1) | ||
| 61 | #define CLK_CNTRL_PRESCALE_EN 1 | ||
| 62 | #define CNT_CNTRL_RESET (1 << 4) | ||
| 63 | |||
| 64 | /** | ||
| 65 | * struct ttc_timer - This definition defines local timer structure | ||
| 66 | * | ||
| 67 | * @base_addr: Base address of timer | ||
| 68 | * @clk: Associated clock source | ||
| 69 | * @clk_rate_change_nb Notifier block for clock rate changes | ||
| 70 | */ | ||
| 71 | struct ttc_timer { | ||
| 72 | void __iomem *base_addr; | ||
| 73 | struct clk *clk; | ||
| 74 | struct notifier_block clk_rate_change_nb; | ||
| 75 | }; | ||
| 76 | |||
| 77 | #define to_ttc_timer(x) \ | ||
| 78 | container_of(x, struct ttc_timer, clk_rate_change_nb) | ||
| 79 | |||
| 80 | struct ttc_timer_clocksource { | ||
| 81 | struct ttc_timer ttc; | ||
| 82 | struct clocksource cs; | ||
| 83 | }; | ||
| 84 | |||
| 85 | #define to_ttc_timer_clksrc(x) \ | ||
| 86 | container_of(x, struct ttc_timer_clocksource, cs) | ||
| 87 | |||
| 88 | struct ttc_timer_clockevent { | ||
| 89 | struct ttc_timer ttc; | ||
| 90 | struct clock_event_device ce; | ||
| 91 | }; | ||
| 92 | |||
| 93 | #define to_ttc_timer_clkevent(x) \ | ||
| 94 | container_of(x, struct ttc_timer_clockevent, ce) | ||
| 95 | |||
| 96 | /** | ||
| 97 | * ttc_set_interval - Set the timer interval value | ||
| 98 | * | ||
| 99 | * @timer: Pointer to the timer instance | ||
| 100 | * @cycles: Timer interval ticks | ||
| 101 | **/ | ||
| 102 | static void ttc_set_interval(struct ttc_timer *timer, | ||
| 103 | unsigned long cycles) | ||
| 104 | { | ||
| 105 | u32 ctrl_reg; | ||
| 106 | |||
| 107 | /* Disable the counter, set the counter value and re-enable counter */ | ||
| 108 | ctrl_reg = __raw_readl(timer->base_addr + TTC_CNT_CNTRL_OFFSET); | ||
| 109 | ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; | ||
| 110 | __raw_writel(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); | ||
| 111 | |||
| 112 | __raw_writel(cycles, timer->base_addr + TTC_INTR_VAL_OFFSET); | ||
| 113 | |||
| 114 | /* | ||
| 115 | * Reset the counter (0x10) so that it starts from 0, one-shot | ||
| 116 | * mode makes this needed for timing to be right. | ||
| 117 | */ | ||
| 118 | ctrl_reg |= CNT_CNTRL_RESET; | ||
| 119 | ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; | ||
| 120 | __raw_writel(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); | ||
| 121 | } | ||
| 122 | |||
| 123 | /** | ||
| 124 | * ttc_clock_event_interrupt - Clock event timer interrupt handler | ||
| 125 | * | ||
| 126 | * @irq: IRQ number of the Timer | ||
| 127 | * @dev_id: void pointer to the ttc_timer instance | ||
| 128 | * | ||
| 129 | * returns: Always IRQ_HANDLED - success | ||
| 130 | **/ | ||
| 131 | static irqreturn_t ttc_clock_event_interrupt(int irq, void *dev_id) | ||
| 132 | { | ||
| 133 | struct ttc_timer_clockevent *ttce = dev_id; | ||
| 134 | struct ttc_timer *timer = &ttce->ttc; | ||
| 135 | |||
| 136 | /* Acknowledge the interrupt and call event handler */ | ||
| 137 | __raw_readl(timer->base_addr + TTC_ISR_OFFSET); | ||
| 138 | |||
| 139 | ttce->ce.event_handler(&ttce->ce); | ||
| 140 | |||
| 141 | return IRQ_HANDLED; | ||
| 142 | } | ||
| 143 | |||
| 144 | /** | ||
| 145 | * __ttc_clocksource_read - Reads the timer counter register | ||
| 146 | * | ||
| 147 | * returns: Current timer counter register value | ||
| 148 | **/ | ||
| 149 | static cycle_t __ttc_clocksource_read(struct clocksource *cs) | ||
| 150 | { | ||
| 151 | struct ttc_timer *timer = &to_ttc_timer_clksrc(cs)->ttc; | ||
| 152 | |||
| 153 | return (cycle_t)__raw_readl(timer->base_addr + | ||
| 154 | TTC_COUNT_VAL_OFFSET); | ||
| 155 | } | ||
| 156 | |||
| 157 | /** | ||
| 158 | * ttc_set_next_event - Sets the time interval for next event | ||
| 159 | * | ||
| 160 | * @cycles: Timer interval ticks | ||
| 161 | * @evt: Address of clock event instance | ||
| 162 | * | ||
| 163 | * returns: Always 0 - success | ||
| 164 | **/ | ||
| 165 | static int ttc_set_next_event(unsigned long cycles, | ||
| 166 | struct clock_event_device *evt) | ||
| 167 | { | ||
| 168 | struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); | ||
| 169 | struct ttc_timer *timer = &ttce->ttc; | ||
| 170 | |||
| 171 | ttc_set_interval(timer, cycles); | ||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | /** | ||
| 176 | * ttc_set_mode - Sets the mode of timer | ||
| 177 | * | ||
| 178 | * @mode: Mode to be set | ||
| 179 | * @evt: Address of clock event instance | ||
| 180 | **/ | ||
| 181 | static void ttc_set_mode(enum clock_event_mode mode, | ||
| 182 | struct clock_event_device *evt) | ||
| 183 | { | ||
| 184 | struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); | ||
| 185 | struct ttc_timer *timer = &ttce->ttc; | ||
| 186 | u32 ctrl_reg; | ||
| 187 | |||
| 188 | switch (mode) { | ||
| 189 | case CLOCK_EVT_MODE_PERIODIC: | ||
| 190 | ttc_set_interval(timer, | ||
| 191 | DIV_ROUND_CLOSEST(clk_get_rate(ttce->ttc.clk), | ||
| 192 | PRESCALE * HZ)); | ||
| 193 | break; | ||
| 194 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 195 | case CLOCK_EVT_MODE_UNUSED: | ||
| 196 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 197 | ctrl_reg = __raw_readl(timer->base_addr + | ||
| 198 | TTC_CNT_CNTRL_OFFSET); | ||
| 199 | ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; | ||
| 200 | __raw_writel(ctrl_reg, | ||
| 201 | timer->base_addr + TTC_CNT_CNTRL_OFFSET); | ||
| 202 | break; | ||
| 203 | case CLOCK_EVT_MODE_RESUME: | ||
| 204 | ctrl_reg = __raw_readl(timer->base_addr + | ||
| 205 | TTC_CNT_CNTRL_OFFSET); | ||
| 206 | ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; | ||
| 207 | __raw_writel(ctrl_reg, | ||
| 208 | timer->base_addr + TTC_CNT_CNTRL_OFFSET); | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | static int ttc_rate_change_clocksource_cb(struct notifier_block *nb, | ||
| 214 | unsigned long event, void *data) | ||
| 215 | { | ||
| 216 | struct clk_notifier_data *ndata = data; | ||
| 217 | struct ttc_timer *ttc = to_ttc_timer(nb); | ||
| 218 | struct ttc_timer_clocksource *ttccs = container_of(ttc, | ||
| 219 | struct ttc_timer_clocksource, ttc); | ||
| 220 | |||
| 221 | switch (event) { | ||
| 222 | case POST_RATE_CHANGE: | ||
| 223 | /* | ||
| 224 | * Do whatever is necessary to maintain a proper time base | ||
| 225 | * | ||
| 226 | * I cannot find a way to adjust the currently used clocksource | ||
| 227 | * to the new frequency. __clocksource_updatefreq_hz() sounds | ||
| 228 | * good, but does not work. Not sure what's that missing. | ||
| 229 | * | ||
| 230 | * This approach works, but triggers two clocksource switches. | ||
| 231 | * The first after unregister to clocksource jiffies. And | ||
| 232 | * another one after the register to the newly registered timer. | ||
| 233 | * | ||
| 234 | * Alternatively we could 'waste' another HW timer to ping pong | ||
| 235 | * between clock sources. That would also use one register and | ||
| 236 | * one unregister call, but only trigger one clocksource switch | ||
| 237 | * for the cost of another HW timer used by the OS. | ||
| 238 | */ | ||
| 239 | clocksource_unregister(&ttccs->cs); | ||
| 240 | clocksource_register_hz(&ttccs->cs, | ||
| 241 | ndata->new_rate / PRESCALE); | ||
| 242 | /* fall through */ | ||
| 243 | case PRE_RATE_CHANGE: | ||
| 244 | case ABORT_RATE_CHANGE: | ||
| 245 | default: | ||
| 246 | return NOTIFY_DONE; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base) | ||
| 251 | { | ||
| 252 | struct ttc_timer_clocksource *ttccs; | ||
| 253 | int err; | ||
| 254 | |||
| 255 | ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL); | ||
| 256 | if (WARN_ON(!ttccs)) | ||
| 257 | return; | ||
| 258 | |||
| 259 | ttccs->ttc.clk = clk; | ||
| 260 | |||
| 261 | err = clk_prepare_enable(ttccs->ttc.clk); | ||
| 262 | if (WARN_ON(err)) { | ||
| 263 | kfree(ttccs); | ||
| 264 | return; | ||
| 265 | } | ||
| 266 | |||
| 267 | ttccs->ttc.clk_rate_change_nb.notifier_call = | ||
| 268 | ttc_rate_change_clocksource_cb; | ||
| 269 | ttccs->ttc.clk_rate_change_nb.next = NULL; | ||
| 270 | if (clk_notifier_register(ttccs->ttc.clk, | ||
| 271 | &ttccs->ttc.clk_rate_change_nb)) | ||
| 272 | pr_warn("Unable to register clock notifier.\n"); | ||
| 273 | |||
| 274 | ttccs->ttc.base_addr = base; | ||
| 275 | ttccs->cs.name = "ttc_clocksource"; | ||
| 276 | ttccs->cs.rating = 200; | ||
| 277 | ttccs->cs.read = __ttc_clocksource_read; | ||
| 278 | ttccs->cs.mask = CLOCKSOURCE_MASK(16); | ||
| 279 | ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; | ||
| 280 | |||
| 281 | /* | ||
| 282 | * Setup the clock source counter to be an incrementing counter | ||
| 283 | * with no interrupt and it rolls over at 0xFFFF. Pre-scale | ||
| 284 | * it by 32 also. Let it start running now. | ||
| 285 | */ | ||
| 286 | __raw_writel(0x0, ttccs->ttc.base_addr + TTC_IER_OFFSET); | ||
| 287 | __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, | ||
| 288 | ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); | ||
| 289 | __raw_writel(CNT_CNTRL_RESET, | ||
| 290 | ttccs->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); | ||
| 291 | |||
| 292 | err = clocksource_register_hz(&ttccs->cs, | ||
| 293 | clk_get_rate(ttccs->ttc.clk) / PRESCALE); | ||
| 294 | if (WARN_ON(err)) { | ||
| 295 | kfree(ttccs); | ||
| 296 | return; | ||
| 297 | } | ||
| 298 | } | ||
| 299 | |||
| 300 | static int ttc_rate_change_clockevent_cb(struct notifier_block *nb, | ||
| 301 | unsigned long event, void *data) | ||
| 302 | { | ||
| 303 | struct clk_notifier_data *ndata = data; | ||
| 304 | struct ttc_timer *ttc = to_ttc_timer(nb); | ||
| 305 | struct ttc_timer_clockevent *ttcce = container_of(ttc, | ||
| 306 | struct ttc_timer_clockevent, ttc); | ||
| 307 | |||
| 308 | switch (event) { | ||
| 309 | case POST_RATE_CHANGE: | ||
| 310 | { | ||
| 311 | unsigned long flags; | ||
| 312 | |||
| 313 | /* | ||
| 314 | * clockevents_update_freq should be called with IRQ disabled on | ||
| 315 | * the CPU the timer provides events for. The timer we use is | ||
| 316 | * common to both CPUs, not sure if we need to run on both | ||
| 317 | * cores. | ||
| 318 | */ | ||
| 319 | local_irq_save(flags); | ||
| 320 | clockevents_update_freq(&ttcce->ce, | ||
| 321 | ndata->new_rate / PRESCALE); | ||
| 322 | local_irq_restore(flags); | ||
| 323 | |||
| 324 | /* fall through */ | ||
| 325 | } | ||
| 326 | case PRE_RATE_CHANGE: | ||
| 327 | case ABORT_RATE_CHANGE: | ||
| 328 | default: | ||
| 329 | return NOTIFY_DONE; | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | static void __init ttc_setup_clockevent(struct clk *clk, | ||
| 334 | void __iomem *base, u32 irq) | ||
| 335 | { | ||
| 336 | struct ttc_timer_clockevent *ttcce; | ||
| 337 | int err; | ||
| 338 | |||
| 339 | ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL); | ||
| 340 | if (WARN_ON(!ttcce)) | ||
| 341 | return; | ||
| 342 | |||
| 343 | ttcce->ttc.clk = clk; | ||
| 344 | |||
| 345 | err = clk_prepare_enable(ttcce->ttc.clk); | ||
| 346 | if (WARN_ON(err)) { | ||
| 347 | kfree(ttcce); | ||
| 348 | return; | ||
| 349 | } | ||
| 350 | |||
| 351 | ttcce->ttc.clk_rate_change_nb.notifier_call = | ||
| 352 | ttc_rate_change_clockevent_cb; | ||
| 353 | ttcce->ttc.clk_rate_change_nb.next = NULL; | ||
| 354 | if (clk_notifier_register(ttcce->ttc.clk, | ||
| 355 | &ttcce->ttc.clk_rate_change_nb)) | ||
| 356 | pr_warn("Unable to register clock notifier.\n"); | ||
| 357 | |||
| 358 | ttcce->ttc.base_addr = base; | ||
| 359 | ttcce->ce.name = "ttc_clockevent"; | ||
| 360 | ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | ||
| 361 | ttcce->ce.set_next_event = ttc_set_next_event; | ||
| 362 | ttcce->ce.set_mode = ttc_set_mode; | ||
| 363 | ttcce->ce.rating = 200; | ||
| 364 | ttcce->ce.irq = irq; | ||
| 365 | ttcce->ce.cpumask = cpu_possible_mask; | ||
| 366 | |||
| 367 | /* | ||
| 368 | * Setup the clock event timer to be an interval timer which | ||
| 369 | * is prescaled by 32 using the interval interrupt. Leave it | ||
| 370 | * disabled for now. | ||
| 371 | */ | ||
| 372 | __raw_writel(0x23, ttcce->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); | ||
| 373 | __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, | ||
| 374 | ttcce->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); | ||
| 375 | __raw_writel(0x1, ttcce->ttc.base_addr + TTC_IER_OFFSET); | ||
| 376 | |||
| 377 | err = request_irq(irq, ttc_clock_event_interrupt, | ||
| 378 | IRQF_DISABLED | IRQF_TIMER, | ||
| 379 | ttcce->ce.name, ttcce); | ||
| 380 | if (WARN_ON(err)) { | ||
| 381 | kfree(ttcce); | ||
| 382 | return; | ||
| 383 | } | ||
| 384 | |||
| 385 | clockevents_config_and_register(&ttcce->ce, | ||
| 386 | clk_get_rate(ttcce->ttc.clk) / PRESCALE, 1, 0xfffe); | ||
| 387 | } | ||
| 388 | |||
| 389 | /** | ||
| 390 | * ttc_timer_init - Initialize the timer | ||
| 391 | * | ||
| 392 | * Initializes the timer hardware and register the clock source and clock event | ||
| 393 | * timers with Linux kernal timer framework | ||
| 394 | */ | ||
| 395 | static void __init ttc_timer_init(struct device_node *timer) | ||
| 396 | { | ||
| 397 | unsigned int irq; | ||
| 398 | void __iomem *timer_baseaddr; | ||
| 399 | struct clk *clk; | ||
| 400 | static int initialized; | ||
| 401 | |||
| 402 | if (initialized) | ||
| 403 | return; | ||
| 404 | |||
| 405 | initialized = 1; | ||
| 406 | |||
| 407 | /* | ||
| 408 | * Get the 1st Triple Timer Counter (TTC) block from the device tree | ||
| 409 | * and use it. Note that the event timer uses the interrupt and it's the | ||
| 410 | * 2nd TTC hence the irq_of_parse_and_map(,1) | ||
| 411 | */ | ||
| 412 | timer_baseaddr = of_iomap(timer, 0); | ||
| 413 | if (!timer_baseaddr) { | ||
| 414 | pr_err("ERROR: invalid timer base address\n"); | ||
| 415 | BUG(); | ||
| 416 | } | ||
| 417 | |||
| 418 | irq = irq_of_parse_and_map(timer, 1); | ||
| 419 | if (irq <= 0) { | ||
| 420 | pr_err("ERROR: invalid interrupt number\n"); | ||
| 421 | BUG(); | ||
| 422 | } | ||
| 423 | |||
| 424 | clk = of_clk_get_by_name(timer, "cpu_1x"); | ||
| 425 | if (IS_ERR(clk)) { | ||
| 426 | pr_err("ERROR: timer input clock not found\n"); | ||
| 427 | BUG(); | ||
| 428 | } | ||
| 429 | |||
| 430 | ttc_setup_clocksource(clk, timer_baseaddr); | ||
| 431 | ttc_setup_clockevent(clk, timer_baseaddr + 4, irq); | ||
| 432 | |||
| 433 | pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq); | ||
| 434 | } | ||
| 435 | |||
| 436 | CLOCKSOURCE_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init); | ||
diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c index bdabdaa8d00f..37f5325bec95 100644 --- a/drivers/clocksource/clksrc-of.c +++ b/drivers/clocksource/clksrc-of.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
| 18 | #include <linux/of.h> | 18 | #include <linux/of.h> |
| 19 | #include <linux/clocksource.h> | ||
| 19 | 20 | ||
| 20 | extern struct of_device_id __clksrc_of_table[]; | 21 | extern struct of_device_id __clksrc_of_table[]; |
| 21 | 22 | ||
| @@ -26,10 +27,10 @@ void __init clocksource_of_init(void) | |||
| 26 | { | 27 | { |
| 27 | struct device_node *np; | 28 | struct device_node *np; |
| 28 | const struct of_device_id *match; | 29 | const struct of_device_id *match; |
| 29 | void (*init_func)(void); | 30 | clocksource_of_init_fn init_func; |
| 30 | 31 | ||
| 31 | for_each_matching_node_and_match(np, __clksrc_of_table, &match) { | 32 | for_each_matching_node_and_match(np, __clksrc_of_table, &match) { |
| 32 | init_func = match->data; | 33 | init_func = match->data; |
| 33 | init_func(); | 34 | init_func(np); |
| 34 | } | 35 | } |
| 35 | } | 36 | } |
diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 0bde03feb095..2e4d8a666c36 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c | |||
| @@ -154,29 +154,12 @@ static struct irqaction tegra_timer_irq = { | |||
| 154 | .dev_id = &tegra_clockevent, | 154 | .dev_id = &tegra_clockevent, |
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| 157 | static const struct of_device_id timer_match[] __initconst = { | 157 | static void __init tegra20_init_timer(struct device_node *np) |
| 158 | { .compatible = "nvidia,tegra20-timer" }, | ||
| 159 | {} | ||
| 160 | }; | ||
| 161 | |||
| 162 | static const struct of_device_id rtc_match[] __initconst = { | ||
| 163 | { .compatible = "nvidia,tegra20-rtc" }, | ||
| 164 | {} | ||
| 165 | }; | ||
| 166 | |||
| 167 | static void __init tegra20_init_timer(void) | ||
| 168 | { | 158 | { |
| 169 | struct device_node *np; | ||
| 170 | struct clk *clk; | 159 | struct clk *clk; |
| 171 | unsigned long rate; | 160 | unsigned long rate; |
| 172 | int ret; | 161 | int ret; |
| 173 | 162 | ||
| 174 | np = of_find_matching_node(NULL, timer_match); | ||
| 175 | if (!np) { | ||
| 176 | pr_err("Failed to find timer DT node\n"); | ||
| 177 | BUG(); | ||
| 178 | } | ||
| 179 | |||
| 180 | timer_reg_base = of_iomap(np, 0); | 163 | timer_reg_base = of_iomap(np, 0); |
| 181 | if (!timer_reg_base) { | 164 | if (!timer_reg_base) { |
| 182 | pr_err("Can't map timer registers\n"); | 165 | pr_err("Can't map timer registers\n"); |
| @@ -200,30 +183,6 @@ static void __init tegra20_init_timer(void) | |||
| 200 | 183 | ||
| 201 | of_node_put(np); | 184 | of_node_put(np); |
| 202 | 185 | ||
| 203 | np = of_find_matching_node(NULL, rtc_match); | ||
| 204 | if (!np) { | ||
| 205 | pr_err("Failed to find RTC DT node\n"); | ||
| 206 | BUG(); | ||
| 207 | } | ||
| 208 | |||
| 209 | rtc_base = of_iomap(np, 0); | ||
| 210 | if (!rtc_base) { | ||
| 211 | pr_err("Can't map RTC registers"); | ||
| 212 | BUG(); | ||
| 213 | } | ||
| 214 | |||
| 215 | /* | ||
| 216 | * rtc registers are used by read_persistent_clock, keep the rtc clock | ||
| 217 | * enabled | ||
| 218 | */ | ||
| 219 | clk = clk_get_sys("rtc-tegra", NULL); | ||
| 220 | if (IS_ERR(clk)) | ||
| 221 | pr_warn("Unable to get rtc-tegra clock\n"); | ||
| 222 | else | ||
| 223 | clk_prepare_enable(clk); | ||
| 224 | |||
| 225 | of_node_put(np); | ||
| 226 | |||
| 227 | switch (rate) { | 186 | switch (rate) { |
| 228 | case 12000000: | 187 | case 12000000: |
| 229 | timer_writel(0x000b, TIMERUS_USEC_CFG); | 188 | timer_writel(0x000b, TIMERUS_USEC_CFG); |
| @@ -259,12 +218,34 @@ static void __init tegra20_init_timer(void) | |||
| 259 | tegra_clockevent.irq = tegra_timer_irq.irq; | 218 | tegra_clockevent.irq = tegra_timer_irq.irq; |
| 260 | clockevents_config_and_register(&tegra_clockevent, 1000000, | 219 | clockevents_config_and_register(&tegra_clockevent, 1000000, |
| 261 | 0x1, 0x1fffffff); | 220 | 0x1, 0x1fffffff); |
| 262 | #ifdef CONFIG_HAVE_ARM_TWD | 221 | } |
| 263 | twd_local_timer_of_register(); | 222 | CLOCKSOURCE_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); |
| 264 | #endif | 223 | |
| 224 | static void __init tegra20_init_rtc(struct device_node *np) | ||
| 225 | { | ||
| 226 | struct clk *clk; | ||
| 227 | |||
| 228 | rtc_base = of_iomap(np, 0); | ||
| 229 | if (!rtc_base) { | ||
| 230 | pr_err("Can't map RTC registers"); | ||
| 231 | BUG(); | ||
| 232 | } | ||
| 233 | |||
| 234 | /* | ||
| 235 | * rtc registers are used by read_persistent_clock, keep the rtc clock | ||
| 236 | * enabled | ||
| 237 | */ | ||
| 238 | clk = clk_get_sys("rtc-tegra", NULL); | ||
| 239 | if (IS_ERR(clk)) | ||
| 240 | pr_warn("Unable to get rtc-tegra clock\n"); | ||
| 241 | else | ||
| 242 | clk_prepare_enable(clk); | ||
| 243 | |||
| 244 | of_node_put(np); | ||
| 245 | |||
| 265 | register_persistent_clock(NULL, tegra_read_persistent_clock); | 246 | register_persistent_clock(NULL, tegra_read_persistent_clock); |
| 266 | } | 247 | } |
| 267 | CLOCKSOURCE_OF_DECLARE(tegra20, "nvidia,tegra20-timer", tegra20_init_timer); | 248 | CLOCKSOURCE_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); |
| 268 | 249 | ||
| 269 | #ifdef CONFIG_PM | 250 | #ifdef CONFIG_PM |
| 270 | static u32 usec_config; | 251 | static u32 usec_config; |
diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index 8efc86b5b5dd..64f553f04fa4 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c | |||
| @@ -129,22 +129,10 @@ static struct irqaction irq = { | |||
| 129 | .dev_id = &clockevent, | 129 | .dev_id = &clockevent, |
| 130 | }; | 130 | }; |
| 131 | 131 | ||
| 132 | static struct of_device_id vt8500_timer_ids[] = { | 132 | static void __init vt8500_timer_init(struct device_node *np) |
| 133 | { .compatible = "via,vt8500-timer" }, | ||
| 134 | { } | ||
| 135 | }; | ||
| 136 | |||
| 137 | static void __init vt8500_timer_init(void) | ||
| 138 | { | 133 | { |
| 139 | struct device_node *np; | ||
| 140 | int timer_irq; | 134 | int timer_irq; |
| 141 | 135 | ||
| 142 | np = of_find_matching_node(NULL, vt8500_timer_ids); | ||
| 143 | if (!np) { | ||
| 144 | pr_err("%s: Timer description missing from Device Tree\n", | ||
| 145 | __func__); | ||
| 146 | return; | ||
| 147 | } | ||
| 148 | regbase = of_iomap(np, 0); | 136 | regbase = of_iomap(np, 0); |
| 149 | if (!regbase) { | 137 | if (!regbase) { |
| 150 | pr_err("%s: Missing iobase description in Device Tree\n", | 138 | pr_err("%s: Missing iobase description in Device Tree\n", |
| @@ -177,4 +165,4 @@ static void __init vt8500_timer_init(void) | |||
| 177 | 4, 0xf0000000); | 165 | 4, 0xf0000000); |
| 178 | } | 166 | } |
| 179 | 167 | ||
| 180 | CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init) | 168 | CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); |
