[lantiq] prepare Makefile for 3.6
[openwrt.git] / target / linux / lantiq / files / arch / mips / lantiq / xway / gptu.c
1 /*
2  *  This program is free software; you can redistribute it and/or modify it
3  *  under the terms of the GNU General Public License version 2 as published
4  *  by the Free Software Foundation.
5  *
6  *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
7  */
8
9 #include <linux/init.h>
10 #include <linux/io.h>
11 #include <linux/ioport.h>
12 #include <linux/pm.h>
13 #include <linux/export.h>
14 #include <linux/delay.h>
15 #include <linux/interrupt.h>
16 #include <asm/reboot.h>
17
18 #include <lantiq_soc.h>
19 #include "../clk.h"
20
21 #include "../devices.h"
22
23 #define ltq_gptu_w32(x, y)      ltq_w32((x), ltq_gptu_membase + (y))
24 #define ltq_gptu_r32(x)         ltq_r32(ltq_gptu_membase + (x))
25
26
27 /* the magic ID byte of the core */
28 #define GPTU_MAGIC      0x59
29 /* clock control register */
30 #define GPTU_CLC        0x00
31 /* id register */
32 #define GPTU_ID         0x08
33 /* interrupt node enable */
34 #define GPTU_IRNEN      0xf4
35 /* interrupt control register */
36 #define GPTU_IRCR       0xf8
37 /* interrupt capture register */
38 #define GPTU_IRNCR      0xfc
39 /* there are 3 identical blocks of 2 timers. calculate register offsets */
40 #define GPTU_SHIFT(x)   (x % 2 ? 4 : 0)
41 #define GPTU_BASE(x)    (((x >> 1) * 0x20) + 0x10)
42 /* timer control register */
43 #define GPTU_CON(x)     (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x00)
44 /* timer auto reload register */
45 #define GPTU_RUN(x)     (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x08)
46 /* timer manual reload register */
47 #define GPTU_RLD(x)     (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x10)
48 /* timer count register */
49 #define GPTU_CNT(x)     (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x18)
50
51 /* GPTU_CON(x) */
52 #define CON_CNT         BIT(2)
53 #define CON_EDGE_FALL   BIT(7)
54 #define CON_SYNC        BIT(8)
55 #define CON_CLK_INT     BIT(10)
56
57 /* GPTU_RUN(x) */
58 #define RUN_SEN         BIT(0)
59 #define RUN_RL          BIT(2)
60
61 /* set clock to runmode */
62 #define CLC_RMC         BIT(8)
63 /* bring core out of suspend */
64 #define CLC_SUSPEND     BIT(4)
65 /* the disable bit */
66 #define CLC_DISABLE     BIT(0)
67
68 #define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22)
69
70 enum gptu_timer {
71         TIMER1A = 0,
72         TIMER1B,
73         TIMER2A,
74         TIMER2B,
75         TIMER3A,
76         TIMER3B
77 };
78
79 static struct resource ltq_gptu_resource =
80         MEM_RES("GPTU", LTQ_GPTU_BASE_ADDR, LTQ_GPTU_SIZE);
81
82 static void __iomem *ltq_gptu_membase;
83
84 static irqreturn_t timer_irq_handler(int irq, void *priv)
85 {
86         int timer = irq - TIMER_INTERRUPT;
87         ltq_gptu_w32(1 << timer, GPTU_IRNCR);
88         return IRQ_HANDLED;
89 }
90
91 static void gptu_hwinit(void)
92 {
93         struct clk *clk = clk_get_sys("ltq_gptu", NULL);
94         clk_enable(clk);
95         ltq_gptu_w32(0x00, GPTU_IRNEN);
96         ltq_gptu_w32(0xff, GPTU_IRNCR);
97         ltq_gptu_w32(CLC_RMC | CLC_SUSPEND, GPTU_CLC);
98 }
99
100 static void gptu_hwexit(void)
101 {
102         ltq_gptu_w32(0x00, GPTU_IRNEN);
103         ltq_gptu_w32(0xff, GPTU_IRNCR);
104         ltq_gptu_w32(CLC_DISABLE, GPTU_CLC);
105 }
106
107 static int ltq_gptu_enable(struct clk *clk)
108 {
109         int ret = request_irq(TIMER_INTERRUPT + clk->bits, timer_irq_handler,
110                 IRQF_TIMER, "timer", NULL);
111         if (ret) {
112                 pr_err("gptu: failed to request irq\n");
113                 return ret;
114         }
115
116         ltq_gptu_w32(CON_CNT | CON_EDGE_FALL | CON_SYNC | CON_CLK_INT,
117                 GPTU_CON(clk->bits));
118         ltq_gptu_w32(1, GPTU_RLD(clk->bits));
119         ltq_gptu_w32(ltq_gptu_r32(GPTU_IRNEN) | clk->bits, GPTU_IRNEN);
120         ltq_gptu_w32(RUN_SEN | RUN_RL, GPTU_RUN(clk->bits));
121         return 0;
122 }
123
124 static void ltq_gptu_disable(struct clk *clk)
125 {
126         ltq_gptu_w32(0, GPTU_RUN(clk->bits));
127         ltq_gptu_w32(0, GPTU_CON(clk->bits));
128         ltq_gptu_w32(0, GPTU_RLD(clk->bits));
129         ltq_gptu_w32(ltq_gptu_r32(GPTU_IRNEN) & ~clk->bits, GPTU_IRNEN);
130         free_irq(TIMER_INTERRUPT + clk->bits, NULL);
131 }
132
133 static inline void clkdev_add_gptu(const char *con, unsigned int timer)
134 {
135         struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
136
137         clk->cl.dev_id = "ltq_gptu";
138         clk->cl.con_id = con;
139         clk->cl.clk = clk;
140         clk->enable = ltq_gptu_enable;
141         clk->disable = ltq_gptu_disable;
142         clk->bits = timer;
143         clkdev_add(&clk->cl);
144 }
145
146 static int __init gptu_setup(void)
147 {
148         /* remap gptu register range */
149         ltq_gptu_membase = ltq_remap_resource(&ltq_gptu_resource);
150         if (!ltq_gptu_membase)
151                 panic("Failed to remap gptu memory");
152
153         /* power up the core */
154         gptu_hwinit();
155
156         /* the gptu has a ID register */
157         if (((ltq_gptu_r32(GPTU_ID) >> 8) & 0xff) != GPTU_MAGIC) {
158                 pr_err("gptu: failed to find magic\n");
159                 gptu_hwexit();
160                 return -ENAVAIL;
161         }
162
163         /* register the clocks */
164         clkdev_add_gptu("timer1a", TIMER1A);
165         clkdev_add_gptu("timer1b", TIMER1B);
166         clkdev_add_gptu("timer2a", TIMER2A);
167         clkdev_add_gptu("timer2b", TIMER2B);
168         clkdev_add_gptu("timer3a", TIMER3A);
169         clkdev_add_gptu("timer3b", TIMER3B);
170
171         pr_info("gptu: 6 timers loaded\n");
172
173         return 0;
174 }
175
176 arch_initcall(gptu_setup);