diff options
Diffstat (limited to 'arch/arm/plat-omap/counter_32k.c')
| -rw-r--r-- | arch/arm/plat-omap/counter_32k.c | 93 |
1 files changed, 40 insertions, 53 deletions
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c index 44ae077dbc28..2132c4f389e1 100644 --- a/arch/arm/plat-omap/counter_32k.c +++ b/arch/arm/plat-omap/counter_32k.c | |||
| @@ -28,19 +28,20 @@ | |||
| 28 | 28 | ||
| 29 | #include <plat/clock.h> | 29 | #include <plat/clock.h> |
| 30 | 30 | ||
| 31 | /* OMAP2_32KSYNCNT_CR_OFF: offset of 32ksync counter register */ | ||
| 32 | #define OMAP2_32KSYNCNT_CR_OFF 0x10 | ||
| 33 | |||
| 31 | /* | 34 | /* |
| 32 | * 32KHz clocksource ... always available, on pretty most chips except | 35 | * 32KHz clocksource ... always available, on pretty most chips except |
| 33 | * OMAP 730 and 1510. Other timers could be used as clocksources, with | 36 | * OMAP 730 and 1510. Other timers could be used as clocksources, with |
| 34 | * higher resolution in free-running counter modes (e.g. 12 MHz xtal), | 37 | * higher resolution in free-running counter modes (e.g. 12 MHz xtal), |
| 35 | * but systems won't necessarily want to spend resources that way. | 38 | * but systems won't necessarily want to spend resources that way. |
| 36 | */ | 39 | */ |
| 37 | static void __iomem *timer_32k_base; | 40 | static void __iomem *sync32k_cnt_reg; |
| 38 | |||
| 39 | #define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410 | ||
| 40 | 41 | ||
| 41 | static u32 notrace omap_32k_read_sched_clock(void) | 42 | static u32 notrace omap_32k_read_sched_clock(void) |
| 42 | { | 43 | { |
| 43 | return timer_32k_base ? __raw_readl(timer_32k_base) : 0; | 44 | return sync32k_cnt_reg ? __raw_readl(sync32k_cnt_reg) : 0; |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 46 | /** | 47 | /** |
| @@ -60,7 +61,7 @@ static void omap_read_persistent_clock(struct timespec *ts) | |||
| 60 | struct timespec *tsp = &persistent_ts; | 61 | struct timespec *tsp = &persistent_ts; |
| 61 | 62 | ||
| 62 | last_cycles = cycles; | 63 | last_cycles = cycles; |
| 63 | cycles = timer_32k_base ? __raw_readl(timer_32k_base) : 0; | 64 | cycles = sync32k_cnt_reg ? __raw_readl(sync32k_cnt_reg) : 0; |
| 64 | delta = cycles - last_cycles; | 65 | delta = cycles - last_cycles; |
| 65 | 66 | ||
| 66 | nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift); | 67 | nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift); |
| @@ -69,55 +70,41 @@ static void omap_read_persistent_clock(struct timespec *ts) | |||
| 69 | *ts = *tsp; | 70 | *ts = *tsp; |
| 70 | } | 71 | } |
| 71 | 72 | ||
| 72 | int __init omap_init_clocksource_32k(void) | 73 | /** |
| 74 | * omap_init_clocksource_32k - setup and register counter 32k as a | ||
| 75 | * kernel clocksource | ||
| 76 | * @pbase: base addr of counter_32k module | ||
| 77 | * @size: size of counter_32k to map | ||
| 78 | * | ||
| 79 | * Returns 0 upon success or negative error code upon failure. | ||
| 80 | * | ||
| 81 | */ | ||
| 82 | int __init omap_init_clocksource_32k(void __iomem *vbase) | ||
| 73 | { | 83 | { |
| 74 | static char err[] __initdata = KERN_ERR | 84 | int ret; |
| 75 | "%s: can't register clocksource!\n"; | 85 | |
| 76 | 86 | /* | |
| 77 | if (cpu_is_omap16xx() || cpu_class_is_omap2()) { | 87 | * 32k sync Counter register offset is at 0x10 |
| 78 | u32 pbase; | 88 | */ |
| 79 | unsigned long size = SZ_4K; | 89 | sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF; |
| 80 | void __iomem *base; | 90 | |
| 81 | struct clk *sync_32k_ick; | 91 | /* |
| 82 | 92 | * 120000 rough estimate from the calculations in | |
| 83 | if (cpu_is_omap16xx()) { | 93 | * __clocksource_updatefreq_scale. |
| 84 | pbase = OMAP16XX_TIMER_32K_SYNCHRONIZED; | 94 | */ |
| 85 | size = SZ_1K; | 95 | clocks_calc_mult_shift(&persistent_mult, &persistent_shift, |
| 86 | } else if (cpu_is_omap2420()) | 96 | 32768, NSEC_PER_SEC, 120000); |
| 87 | pbase = OMAP2420_32KSYNCT_BASE + 0x10; | 97 | |
| 88 | else if (cpu_is_omap2430()) | 98 | ret = clocksource_mmio_init(sync32k_cnt_reg, "32k_counter", 32768, |
| 89 | pbase = OMAP2430_32KSYNCT_BASE + 0x10; | 99 | 250, 32, clocksource_mmio_readl_up); |
| 90 | else if (cpu_is_omap34xx()) | 100 | if (ret) { |
| 91 | pbase = OMAP3430_32KSYNCT_BASE + 0x10; | 101 | pr_err("32k_counter: can't register clocksource\n"); |
| 92 | else if (cpu_is_omap44xx()) | 102 | return ret; |
| 93 | pbase = OMAP4430_32KSYNCT_BASE + 0x10; | ||
| 94 | else | ||
| 95 | return -ENODEV; | ||
| 96 | |||
| 97 | /* For this to work we must have a static mapping in io.c for this area */ | ||
| 98 | base = ioremap(pbase, size); | ||
| 99 | if (!base) | ||
| 100 | return -ENODEV; | ||
| 101 | |||
| 102 | sync_32k_ick = clk_get(NULL, "omap_32ksync_ick"); | ||
| 103 | if (!IS_ERR(sync_32k_ick)) | ||
| 104 | clk_enable(sync_32k_ick); | ||
| 105 | |||
| 106 | timer_32k_base = base; | ||
| 107 | |||
| 108 | /* | ||
| 109 | * 120000 rough estimate from the calculations in | ||
| 110 | * __clocksource_updatefreq_scale. | ||
| 111 | */ | ||
| 112 | clocks_calc_mult_shift(&persistent_mult, &persistent_shift, | ||
| 113 | 32768, NSEC_PER_SEC, 120000); | ||
| 114 | |||
| 115 | if (clocksource_mmio_init(base, "32k_counter", 32768, 250, 32, | ||
| 116 | clocksource_mmio_readl_up)) | ||
| 117 | printk(err, "32k_counter"); | ||
| 118 | |||
| 119 | setup_sched_clock(omap_32k_read_sched_clock, 32, 32768); | ||
| 120 | register_persistent_clock(NULL, omap_read_persistent_clock); | ||
| 121 | } | 103 | } |
| 104 | |||
| 105 | setup_sched_clock(omap_32k_read_sched_clock, 32, 32768); | ||
| 106 | register_persistent_clock(NULL, omap_read_persistent_clock); | ||
| 107 | pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n"); | ||
| 108 | |||
| 122 | return 0; | 109 | return 0; |
| 123 | } | 110 | } |
