add new target 'oxnas'
[openwrt.git] / target / linux / oxnas / files / drivers / clocksource / oxnas_rps_timer.c
1 /*
2  * arch/arm/mach-ox820/rps-time.c
3  *
4  * Copyright (C) 2009 Oxford Semiconductor Ltd
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <linux/init.h>
20 #include <linux/interrupt.h>
21 #include <linux/irq.h>
22 #include <linux/io.h>
23 #include <linux/clockchips.h>
24 #include <linux/clk.h>
25 #include <linux/of_irq.h>
26 #include <linux/of_address.h>
27 #include <linux/sched_clock.h>
28 #include <mach/hardware.h>
29
30 enum {
31         TIMER_LOAD = 0,
32         TIMER_CURR = 4,
33         TIMER_CTRL = 8,
34         TIMER_CLRINT = 0xC,
35
36         TIMER_BITS = 24,
37
38         TIMER_MAX_VAL = (1 << TIMER_BITS) - 1,
39
40         TIMER_PERIODIC = (1 << 6),
41         TIMER_ENABLE = (1 << 7),
42
43         TIMER_DIV1  = (0 << 2),
44         TIMER_DIV16  = (1 << 2),
45         TIMER_DIV256  = (2 << 2),
46
47         TIMER1_OFFSET = 0,
48         TIMER2_OFFSET = 0x20,
49
50 };
51
52 static u64 notrace rps_read_sched_clock(void)
53 {
54         return ~readl_relaxed(RPSA_TIMER2_VAL);
55 }
56
57 static void __init rps_clocksource_init(void __iomem *base, ulong ref_rate)
58 {
59         int ret;
60         ulong clock_rate;
61         /* use prescale 16 */
62         clock_rate = ref_rate / 16;
63
64         iowrite32(TIMER_MAX_VAL, base + TIMER_LOAD);
65         iowrite32(TIMER_PERIODIC | TIMER_ENABLE | TIMER_DIV16,
66                         base + TIMER_CTRL);
67
68         ret = clocksource_mmio_init(base + TIMER_CURR, "rps_clocksource_timer",
69                                         clock_rate, 250, TIMER_BITS,
70                                         clocksource_mmio_readl_down);
71         if (ret)
72                 panic("can't register clocksource\n");
73
74         sched_clock_register(rps_read_sched_clock, TIMER_BITS, clock_rate);
75 }
76
77 static void __init rps_timer_init(struct device_node *np)
78 {
79         struct clk *refclk;
80         unsigned long ref_rate;
81         void __iomem *base;
82
83         refclk = of_clk_get(np, 0);
84
85         if (IS_ERR(refclk) || clk_prepare_enable(refclk))
86                 panic("rps_timer_init: failed to get refclk\n");
87         ref_rate = clk_get_rate(refclk);
88
89         base = of_iomap(np, 0);
90         if (!base)
91                 panic("rps_timer_init: failed to map io\n");
92
93         rps_clocksource_init(base + TIMER2_OFFSET, ref_rate);
94 }
95
96 CLOCKSOURCE_OF_DECLARE(nas782x, "plxtech,nas782x-rps-timer", rps_timer_init);