Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
mips
lantiq
xway
gptu.c
Go to the documentation of this file.
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 <
[email protected]
>
7
* Copyright (C) 2012 Lantiq GmbH
8
*/
9
10
#include <
linux/interrupt.h
>
11
#include <
linux/ioport.h
>
12
#include <linux/module.h>
13
#include <
linux/of_platform.h
>
14
#include <
linux/of_irq.h
>
15
16
#include <lantiq_soc.h>
17
#include "../clk.h"
18
19
/* the magic ID byte of the core */
20
#define GPTU_MAGIC 0x59
21
/* clock control register */
22
#define GPTU_CLC 0x00
23
/* id register */
24
#define GPTU_ID 0x08
25
/* interrupt node enable */
26
#define GPTU_IRNEN 0xf4
27
/* interrupt control register */
28
#define GPTU_IRCR 0xf8
29
/* interrupt capture register */
30
#define GPTU_IRNCR 0xfc
31
/* there are 3 identical blocks of 2 timers. calculate register offsets */
32
#define GPTU_SHIFT(x) (x % 2 ? 4 : 0)
33
#define GPTU_BASE(x) (((x >> 1) * 0x20) + 0x10)
34
/* timer control register */
35
#define GPTU_CON(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x00)
36
/* timer auto reload register */
37
#define GPTU_RUN(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x08)
38
/* timer manual reload register */
39
#define GPTU_RLD(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x10)
40
/* timer count register */
41
#define GPTU_CNT(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x18)
42
43
/* GPTU_CON(x) */
44
#define CON_CNT BIT(2)
45
#define CON_EDGE_ANY (BIT(7) | BIT(6))
46
#define CON_SYNC BIT(8)
47
#define CON_CLK_INT BIT(10)
48
49
/* GPTU_RUN(x) */
50
#define RUN_SEN BIT(0)
51
#define RUN_RL BIT(2)
52
53
/* set clock to runmode */
54
#define CLC_RMC BIT(8)
55
/* bring core out of suspend */
56
#define CLC_SUSPEND BIT(4)
57
/* the disable bit */
58
#define CLC_DISABLE BIT(0)
59
60
#define gptu_w32(x, y) ltq_w32((x), gptu_membase + (y))
61
#define gptu_r32(x) ltq_r32(gptu_membase + (x))
62
63
enum
gptu_timer
{
64
TIMER1A
= 0,
65
TIMER1B
,
66
TIMER2A
,
67
TIMER2B
,
68
TIMER3A
,
69
TIMER3B
70
};
71
72
static
void
__iomem
*gptu_membase;
73
static
struct
resource
irqres[6];
74
75
static
irqreturn_t
timer_irq_handler(
int
irq,
void
*
priv
)
76
{
77
int
timer
= irq - irqres[0].start;
78
gptu_w32
(1 << timer,
GPTU_IRNCR
);
79
return
IRQ_HANDLED
;
80
}
81
82
static
void
gptu_hwinit(
void
)
83
{
84
gptu_w32
(0x00,
GPTU_IRNEN
);
85
gptu_w32
(0xff,
GPTU_IRNCR
);
86
gptu_w32
(
CLC_RMC
|
CLC_SUSPEND
,
GPTU_CLC
);
87
}
88
89
static
void
gptu_hwexit(
void
)
90
{
91
gptu_w32
(0x00,
GPTU_IRNEN
);
92
gptu_w32
(0xff,
GPTU_IRNCR
);
93
gptu_w32
(
CLC_DISABLE
,
GPTU_CLC
);
94
}
95
96
static
int
gptu_enable(
struct
clk
*
clk
)
97
{
98
int
ret
=
request_irq
(irqres[clk->
bits
].start, timer_irq_handler,
99
IRQF_TIMER
,
"gtpu"
,
NULL
);
100
if
(ret) {
101
pr_err
(
"gptu: failed to request irq\n"
);
102
return
ret
;
103
}
104
105
gptu_w32
(
CON_CNT
|
CON_EDGE_ANY
|
CON_SYNC
|
CON_CLK_INT
,
106
GPTU_CON
(clk->
bits
));
107
gptu_w32
(1,
GPTU_RLD
(clk->
bits
));
108
gptu_w32
(
gptu_r32
(
GPTU_IRNEN
) |
BIT
(clk->
bits
),
GPTU_IRNEN
);
109
gptu_w32
(
RUN_SEN
|
RUN_RL
,
GPTU_RUN
(clk->
bits
));
110
return
0;
111
}
112
113
static
void
gptu_disable(
struct
clk *clk)
114
{
115
gptu_w32
(0,
GPTU_RUN
(clk->
bits
));
116
gptu_w32
(0,
GPTU_CON
(clk->
bits
));
117
gptu_w32
(0,
GPTU_RLD
(clk->
bits
));
118
gptu_w32
(
gptu_r32
(
GPTU_IRNEN
) & ~
BIT
(clk->
bits
),
GPTU_IRNEN
);
119
free_irq
(irqres[clk->
bits
].start,
NULL
);
120
}
121
122
static
inline
void
clkdev_add_gptu(
struct
device
*
dev
,
const
char
*
con
,
123
unsigned
int
timer
)
124
{
125
struct
clk *clk = kzalloc(
sizeof
(
struct
clk),
GFP_KERNEL
);
126
127
clk->
cl
.dev_id = dev_name(dev);
128
clk->
cl
.con_id =
con
;
129
clk->
cl
.clk = clk;
130
clk->
enable
= gptu_enable;
131
clk->
disable
= gptu_disable;
132
clk->
bits
=
timer
;
133
clkdev_add
(&clk->
cl
);
134
}
135
136
static
int
__devinit
gptu_probe(
struct
platform_device
*pdev)
137
{
138
struct
clk *clk;
139
struct
resource
*
res
;
140
141
if
(
of_irq_to_resource_table
(pdev->
dev
.of_node, irqres, 6) != 6) {
142
dev_err
(&pdev->
dev
,
"Failed to get IRQ list\n"
);
143
return
-
EINVAL
;
144
}
145
146
res =
platform_get_resource
(pdev,
IORESOURCE_MEM
, 0);
147
if
(!res) {
148
dev_err
(&pdev->
dev
,
"Failed to get resource\n"
);
149
return
-
ENOMEM
;
150
}
151
152
/* remap gptu register range */
153
gptu_membase =
devm_request_and_ioremap
(&pdev->
dev
, res);
154
if
(!gptu_membase) {
155
dev_err
(&pdev->
dev
,
"Failed to remap resource\n"
);
156
return
-
ENOMEM
;
157
}
158
159
/* enable our clock */
160
clk =
clk_get
(&pdev->
dev
,
NULL
);
161
if
(IS_ERR(clk)) {
162
dev_err
(&pdev->
dev
,
"Failed to get clock\n"
);
163
return
-
ENOENT
;
164
}
165
clk_enable
(clk);
166
167
/* power up the core */
168
gptu_hwinit();
169
170
/* the gptu has a ID register */
171
if
(((
gptu_r32
(
GPTU_ID
) >> 8) & 0xff) !=
GPTU_MAGIC
) {
172
dev_err
(&pdev->
dev
,
"Failed to find magic\n"
);
173
gptu_hwexit();
174
return
-
ENAVAIL
;
175
}
176
177
/* register the clocks */
178
clkdev_add_gptu(&pdev->
dev
,
"timer1a"
,
TIMER1A
);
179
clkdev_add_gptu(&pdev->
dev
,
"timer1b"
,
TIMER1B
);
180
clkdev_add_gptu(&pdev->
dev
,
"timer2a"
,
TIMER2A
);
181
clkdev_add_gptu(&pdev->
dev
,
"timer2b"
,
TIMER2B
);
182
clkdev_add_gptu(&pdev->
dev
,
"timer3a"
,
TIMER3A
);
183
clkdev_add_gptu(&pdev->
dev
,
"timer3b"
,
TIMER3B
);
184
185
dev_info
(&pdev->
dev
,
"gptu: 6 timers loaded\n"
);
186
187
return
0;
188
}
189
190
static
const
struct
of_device_id
gptu_match[] = {
191
{ .compatible =
"lantiq,gptu-xway"
},
192
{},
193
};
194
MODULE_DEVICE_TABLE
(of, dma_match);
195
196
static
struct
platform_driver
dma_driver = {
197
.probe = gptu_probe,
198
.driver = {
199
.name =
"gptu-xway"
,
200
.owner =
THIS_MODULE
,
201
.of_match_table = gptu_match,
202
},
203
};
204
205
int
__init
gptu_init
(
void
)
206
{
207
int
ret =
platform_driver_register
(&dma_driver);
208
209
if
(ret)
210
pr_info
(
"gptu: Error registering platform driver\n"
);
211
return
ret
;
212
}
213
214
arch_initcall
(
gptu_init
);
Generated on Thu Jan 10 2013 13:11:28 for Linux Kernel by
1.8.2