diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-01 23:18:05 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-01 23:18:05 -0400 |
| commit | ac5761a650d22dd7dfad4d417463a0981d2da0a4 (patch) | |
| tree | c01a46a889dde74fbbb05d3b2da22387bb4875c6 /drivers/clocksource | |
| parent | 25498e5b3df931a3d52a6e0642ae242e4ee19488 (diff) | |
| parent | eed1e576507b52e03e549e0c9e0c747978122403 (diff) | |
Merge branch 'next/timer' of git://git.linaro.org/people/arnd/arm-soc
* 'next/timer' of git://git.linaro.org/people/arnd/arm-soc:
clocksource: fixup ux500 build problems
ARM: omap: use __devexit_p in dmtimer driver
ARM: ux500: Reprogram timers upon resume
ARM: plat-nomadik: timer: Export reset functions
ARM: plat-nomadik: timer: Add support for periodic timers
ARM: ux500: Move timer code to separate file
ARM: ux500: add support for clocksource DBX500 PRCMU
clocksource: add DBX500 PRCMU Timer support
ARM: plat-nomadik: MTU sched_clock as an option
ARM: OMAP: dmtimer: add error handling to export APIs
ARM: OMAP: dmtimer: low-power mode support
ARM: OMAP: dmtimer: skip reserved timers
ARM: OMAP: dmtimer: pm_runtime support
ARM: OMAP: dmtimer: switch-over to platform device driver
ARM: OMAP: dmtimer: platform driver
ARM: OMAP2+: dmtimer: convert to platform devices
ARM: OMAP1: dmtimer: conversion to platform devices
ARM: OMAP2+: dmtimer: add device names to flck nodes
ARM: OMAP: Add support for dmtimer v2 ip
Diffstat (limited to 'drivers/clocksource')
| -rw-r--r-- | drivers/clocksource/Kconfig | 15 | ||||
| -rw-r--r-- | drivers/clocksource/Makefile | 1 | ||||
| -rw-r--r-- | drivers/clocksource/clksrc-dbx500-prcmu.c | 106 |
3 files changed, 122 insertions, 0 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 34e9c4f88926..999d6a03e436 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
| @@ -15,3 +15,18 @@ config CLKSRC_MMIO | |||
| 15 | 15 | ||
| 16 | config DW_APB_TIMER | 16 | config DW_APB_TIMER |
| 17 | bool | 17 | bool |
| 18 | |||
| 19 | config CLKSRC_DBX500_PRCMU | ||
| 20 | bool "Clocksource PRCMU Timer" | ||
| 21 | depends on UX500_SOC_DB5500 || UX500_SOC_DB8500 | ||
| 22 | default y | ||
| 23 | help | ||
| 24 | Use the always on PRCMU Timer as clocksource | ||
| 25 | |||
| 26 | config CLKSRC_DBX500_PRCMU_SCHED_CLOCK | ||
| 27 | bool "Clocksource PRCMU Timer sched_clock" | ||
| 28 | depends on (CLKSRC_DBX500_PRCMU && !NOMADIK_MTU_SCHED_CLOCK) | ||
| 29 | select HAVE_SCHED_CLOCK | ||
| 30 | default y | ||
| 31 | help | ||
| 32 | Use the always on PRCMU Timer as sched_clock | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 85ad1646a7b7..8d81a1d32653 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
| @@ -9,3 +9,4 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o | |||
| 9 | obj-$(CONFIG_CLKBLD_I8253) += i8253.o | 9 | obj-$(CONFIG_CLKBLD_I8253) += i8253.o |
| 10 | obj-$(CONFIG_CLKSRC_MMIO) += mmio.o | 10 | obj-$(CONFIG_CLKSRC_MMIO) += mmio.o |
| 11 | obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o | 11 | obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o |
| 12 | obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o \ No newline at end of file | ||
diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c new file mode 100644 index 000000000000..59feefe0e3e6 --- /dev/null +++ b/drivers/clocksource/clksrc-dbx500-prcmu.c | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2011 | ||
| 3 | * | ||
| 4 | * License Terms: GNU General Public License v2 | ||
| 5 | * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson | ||
| 6 | * Author: Sundar Iyer for ST-Ericsson | ||
| 7 | * sched_clock implementation is based on: | ||
| 8 | * plat-nomadik/timer.c Linus Walleij <linus.walleij@stericsson.com> | ||
| 9 | * | ||
| 10 | * DBx500-PRCMU Timer | ||
| 11 | * The PRCMU has 5 timers which are available in a always-on | ||
| 12 | * power domain. We use the Timer 4 for our always-on clock | ||
| 13 | * source on DB8500 and Timer 3 on DB5500. | ||
| 14 | */ | ||
| 15 | #include <linux/clockchips.h> | ||
| 16 | #include <linux/clksrc-dbx500-prcmu.h> | ||
| 17 | |||
| 18 | #include <asm/sched_clock.h> | ||
| 19 | |||
| 20 | #include <mach/setup.h> | ||
| 21 | #include <mach/hardware.h> | ||
| 22 | |||
| 23 | #define RATE_32K 32768 | ||
| 24 | |||
| 25 | #define TIMER_MODE_CONTINOUS 0x1 | ||
| 26 | #define TIMER_DOWNCOUNT_VAL 0xffffffff | ||
| 27 | |||
| 28 | #define PRCMU_TIMER_REF 0 | ||
| 29 | #define PRCMU_TIMER_DOWNCOUNT 0x4 | ||
| 30 | #define PRCMU_TIMER_MODE 0x8 | ||
| 31 | |||
| 32 | #define SCHED_CLOCK_MIN_WRAP 131072 /* 2^32 / 32768 */ | ||
| 33 | |||
| 34 | static void __iomem *clksrc_dbx500_timer_base; | ||
| 35 | |||
| 36 | static cycle_t clksrc_dbx500_prcmu_read(struct clocksource *cs) | ||
| 37 | { | ||
| 38 | u32 count, count2; | ||
| 39 | |||
| 40 | do { | ||
| 41 | count = readl(clksrc_dbx500_timer_base + | ||
| 42 | PRCMU_TIMER_DOWNCOUNT); | ||
| 43 | count2 = readl(clksrc_dbx500_timer_base + | ||
| 44 | PRCMU_TIMER_DOWNCOUNT); | ||
| 45 | } while (count2 != count); | ||
| 46 | |||
| 47 | /* Negate because the timer is a decrementing counter */ | ||
| 48 | return ~count; | ||
| 49 | } | ||
| 50 | |||
| 51 | static struct clocksource clocksource_dbx500_prcmu = { | ||
| 52 | .name = "dbx500-prcmu-timer", | ||
| 53 | .rating = 300, | ||
| 54 | .read = clksrc_dbx500_prcmu_read, | ||
| 55 | .shift = 10, | ||
| 56 | .mask = CLOCKSOURCE_MASK(32), | ||
| 57 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
| 58 | }; | ||
| 59 | |||
| 60 | #ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK | ||
| 61 | static DEFINE_CLOCK_DATA(cd); | ||
| 62 | |||
| 63 | unsigned long long notrace sched_clock(void) | ||
| 64 | { | ||
| 65 | u32 cyc; | ||
| 66 | |||
| 67 | if (unlikely(!clksrc_dbx500_timer_base)) | ||
| 68 | return 0; | ||
| 69 | |||
| 70 | cyc = clksrc_dbx500_prcmu_read(&clocksource_dbx500_prcmu); | ||
| 71 | |||
| 72 | return cyc_to_sched_clock(&cd, cyc, (u32)~0); | ||
| 73 | } | ||
| 74 | |||
| 75 | static void notrace clksrc_dbx500_prcmu_update_sched_clock(void) | ||
| 76 | { | ||
| 77 | u32 cyc = clksrc_dbx500_prcmu_read(&clocksource_dbx500_prcmu); | ||
| 78 | update_sched_clock(&cd, cyc, (u32)~0); | ||
| 79 | } | ||
| 80 | #endif | ||
| 81 | |||
| 82 | void __init clksrc_dbx500_prcmu_init(void __iomem *base) | ||
| 83 | { | ||
| 84 | clksrc_dbx500_timer_base = base; | ||
| 85 | |||
| 86 | /* | ||
| 87 | * The A9 sub system expects the timer to be configured as | ||
| 88 | * a continous looping timer. | ||
| 89 | * The PRCMU should configure it but if it for some reason | ||
| 90 | * don't we do it here. | ||
| 91 | */ | ||
| 92 | if (readl(clksrc_dbx500_timer_base + PRCMU_TIMER_MODE) != | ||
| 93 | TIMER_MODE_CONTINOUS) { | ||
| 94 | writel(TIMER_MODE_CONTINOUS, | ||
| 95 | clksrc_dbx500_timer_base + PRCMU_TIMER_MODE); | ||
| 96 | writel(TIMER_DOWNCOUNT_VAL, | ||
| 97 | clksrc_dbx500_timer_base + PRCMU_TIMER_REF); | ||
| 98 | } | ||
| 99 | #ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK | ||
| 100 | init_sched_clock(&cd, clksrc_dbx500_prcmu_update_sched_clock, | ||
| 101 | 32, RATE_32K); | ||
| 102 | #endif | ||
| 103 | clocksource_calc_mult_shift(&clocksource_dbx500_prcmu, | ||
| 104 | RATE_32K, SCHED_CLOCK_MIN_WRAP); | ||
| 105 | clocksource_register(&clocksource_dbx500_prcmu); | ||
| 106 | } | ||
