ARM: 5973/1: ux500: add gpio support
[deliverable/linux.git] / arch / arm / plat-nomadik / timer.c
CommitLineData
28ad94ec
AR
1/*
2 * linux/arch/arm/mach-nomadik/timer.c
3 *
4 * Copyright (C) 2008 STMicroelectronics
5 * Copyright (C) 2009 Alessandro Rubini, somewhat based on at91sam926x
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2, as
9 * published by the Free Software Foundation.
10 */
11#include <linux/init.h>
12#include <linux/interrupt.h>
13#include <linux/irq.h>
14#include <linux/io.h>
15#include <linux/clockchips.h>
16#include <linux/jiffies.h>
17#include <asm/mach/time.h>
28ad94ec 18
59b559d7 19#include <plat/mtu.h>
28ad94ec
AR
20
21static u32 nmdk_count; /* accumulated count */
22static u32 nmdk_cycle; /* write-once */
59b559d7
SK
23
24/* setup by the platform code */
25void __iomem *mtu_base;
28ad94ec
AR
26
27/*
28 * clocksource: the MTU device is a decrementing counters, so we negate
29 * the value being read.
30 */
31static cycle_t nmdk_read_timer(struct clocksource *cs)
32{
33 u32 count = readl(mtu_base + MTU_VAL(0));
34 return nmdk_count + nmdk_cycle - count;
35
36}
37
38static struct clocksource nmdk_clksrc = {
39 .name = "mtu_0",
40 .rating = 120,
41 .read = nmdk_read_timer,
42 .shift = 20,
43 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
44};
45
46/*
47 * Clockevent device: currently only periodic mode is supported
48 */
49static void nmdk_clkevt_mode(enum clock_event_mode mode,
50 struct clock_event_device *dev)
51{
28ad94ec
AR
52 switch (mode) {
53 case CLOCK_EVT_MODE_PERIODIC:
a602f0f2 54 /* count current value? */
28ad94ec 55 writel(readl(mtu_base + MTU_IMSC) | 1, mtu_base + MTU_IMSC);
28ad94ec
AR
56 break;
57 case CLOCK_EVT_MODE_ONESHOT:
58 BUG(); /* Not supported, yet */
59 /* FALLTHROUGH */
60 case CLOCK_EVT_MODE_SHUTDOWN:
61 case CLOCK_EVT_MODE_UNUSED:
28ad94ec 62 writel(readl(mtu_base + MTU_IMSC) & ~1, mtu_base + MTU_IMSC);
28ad94ec
AR
63 break;
64 case CLOCK_EVT_MODE_RESUME:
65 break;
66 }
67}
68
69static struct clock_event_device nmdk_clkevt = {
70 .name = "mtu_0",
71 .features = CLOCK_EVT_FEAT_PERIODIC,
72 .shift = 32,
73 .rating = 100,
74 .set_mode = nmdk_clkevt_mode,
75};
76
77/*
78 * IRQ Handler for the timer 0 of the MTU block. The irq is not shared
79 * as we are the only users of mtu0 by now.
80 */
81static irqreturn_t nmdk_timer_interrupt(int irq, void *dev_id)
82{
83 /* ack: "interrupt clear register" */
59b559d7 84 writel(1 << 0, mtu_base + MTU_ICR);
28ad94ec
AR
85
86 /* we can't count lost ticks, unfortunately */
87 nmdk_count += nmdk_cycle;
88 nmdk_clkevt.event_handler(&nmdk_clkevt);
89
90 return IRQ_HANDLED;
91}
92
93/*
94 * Set up timer interrupt, and return the current time in seconds.
95 */
96static struct irqaction nmdk_timer_irq = {
97 .name = "Nomadik Timer Tick",
98 .flags = IRQF_DISABLED | IRQF_TIMER,
99 .handler = nmdk_timer_interrupt,
100};
101
102static void nmdk_timer_reset(void)
103{
104 u32 cr;
105
106 writel(0, mtu_base + MTU_CR(0)); /* off */
107
108 /* configure load and background-load, and fire it up */
109 writel(nmdk_cycle, mtu_base + MTU_LR(0));
110 writel(nmdk_cycle, mtu_base + MTU_BGLR(0));
111 cr = MTU_CRn_PERIODIC | MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS;
112 writel(cr, mtu_base + MTU_CR(0));
113 writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
114}
115
59b559d7 116void __init nmdk_timer_init(void)
28ad94ec 117{
28ad94ec
AR
118 unsigned long rate;
119 int bits;
120
121 rate = CLOCK_TICK_RATE; /* 2.4MHz */
122 nmdk_cycle = (rate + HZ/2) / HZ;
123
28ad94ec
AR
124 /* Init the timer and register clocksource */
125 nmdk_timer_reset();
126
127 nmdk_clksrc.mult = clocksource_hz2mult(rate, nmdk_clksrc.shift);
128 bits = 8*sizeof(nmdk_count);
129 nmdk_clksrc.mask = CLOCKSOURCE_MASK(bits);
130
59b559d7
SK
131 if (clocksource_register(&nmdk_clksrc))
132 printk(KERN_ERR "timer: failed to initialize clock "
133 "source %s\n", nmdk_clksrc.name);
28ad94ec
AR
134
135 /* Register irq and clockevents */
136 setup_irq(IRQ_MTU0, &nmdk_timer_irq);
137 nmdk_clkevt.mult = div_sc(rate, NSEC_PER_SEC, nmdk_clkevt.shift);
138 nmdk_clkevt.cpumask = cpumask_of(0);
139 clockevents_register_device(&nmdk_clkevt);
140}
This page took 0.081017 seconds and 5 git commands to generate.