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
30enum {
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
52static u64 notrace rps_read_sched_clock(void)
53{
54	return ~readl_relaxed(RPSA_TIMER2_VAL);
55}
56
57static 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
77static 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
96CLOCKSOURCE_OF_DECLARE(nas782x, "plxtech,nas782x-rps-timer", rps_timer_init);
97