aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2008-10-31 12:14:33 -0400
committerBen Dooks <ben-linux@fluff.org>2008-12-15 18:33:59 -0500
commit89d043c3db22c37523165905708d2fa8062fda86 (patch)
tree53d66e6fdde2ef3288ac06f229e3ca626ff88722 /arch/arm
parent8a53bdb907cb924ed30f79bcfe7f4f15ff7de15e (diff)
[ARM] S3C64XX: GPIO library support
Add gpiolib registration for the GPIOs available on the S3C64XX platform Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/plat-s3c64xx/Makefile1
-rw-r--r--arch/arm/plat-s3c64xx/gpiolib.c347
-rw-r--r--arch/arm/plat-s3c64xx/include/plat/regs-gpio.h35
3 files changed, 383 insertions, 0 deletions
diff --git a/arch/arm/plat-s3c64xx/Makefile b/arch/arm/plat-s3c64xx/Makefile
index 9c09b0819805..a5b7c388351e 100644
--- a/arch/arm/plat-s3c64xx/Makefile
+++ b/arch/arm/plat-s3c64xx/Makefile
@@ -17,6 +17,7 @@ obj-y += cpu.o
17obj-y += irq.o 17obj-y += irq.o
18obj-y += irq-eint.o 18obj-y += irq-eint.o
19obj-y += clock.o 19obj-y += clock.o
20obj-y += gpiolib.o
20 21
21# CPU support 22# CPU support
22 23
diff --git a/arch/arm/plat-s3c64xx/gpiolib.c b/arch/arm/plat-s3c64xx/gpiolib.c
new file mode 100644
index 000000000000..28ba23502bce
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/gpiolib.c
@@ -0,0 +1,347 @@
1/* arch/arm/plat-s3c64xx/gpiolib.c
2 *
3 * Copyright 2008 Openmoko, Inc.
4 * Copyright 2008 Simtec Electronics
5 * Ben Dooks <ben@simtec.co.uk>
6 * http://armlinux.simtec.co.uk/
7 *
8 * S3C64XX - GPIOlib support
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/kernel.h>
16#include <linux/irq.h>
17#include <linux/io.h>
18
19#include <mach/map.h>
20#include <mach/gpio.h>
21
22#include <plat/gpio-core.h>
23#include <plat/regs-gpio.h>
24
25/* GPIO bank summary:
26 *
27 * Bank GPIOs Style SlpCon ExtInt Group
28 * A 8 4Bit Yes 1
29 * B 7 4Bit Yes 1
30 * C 8 4Bit Yes 2
31 * D 5 4Bit Yes 3
32 * E 5 4Bit Yes None
33 * F 16 2Bit Yes 4 [1]
34 * G 7 4Bit Yes 5
35 * H 10 4Bit[2] Yes 6
36 * I 16 2Bit Yes None
37 * J 12 2Bit Yes None
38 * K 16 4Bit[2] No None
39 * L 15 4Bit[2] No None
40 * M 6 4Bit No IRQ_EINT
41 * N 16 2Bit No IRQ_EINT
42 * O 16 2Bit Yes 7
43 * P 15 2Bit Yes 8
44 * Q 9 2Bit Yes 9
45 *
46 * [1] BANKF pins 14,15 do not form part of the external interrupt sources
47 * [2] BANK has two control registers, GPxCON0 and GPxCON1
48 */
49
50#define OFF_GPCON (0x00)
51#define OFF_GPDAT (0x04)
52
53#define con_4bit_shift(__off) ((__off) * 4)
54
55/* The s3c64xx_gpiolib_4bit routines are to control the gpio banks where
56 * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
57 * following example:
58 *
59 * base + 0x00: Control register, 4 bits per gpio
60 * gpio n: 4 bits starting at (4*n)
61 * 0000 = input, 0001 = output, others mean special-function
62 * base + 0x04: Data register, 1 bit per gpio
63 * bit n: data bit n
64 *
65 * Note, since the data register is one bit per gpio and is at base + 0x4
66 * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
67 * the output.
68*/
69
70static int s3c64xx_gpiolib_4bit_input(struct gpio_chip *chip, unsigned offset)
71{
72 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
73 void __iomem *base = ourchip->base;
74 unsigned long con;
75
76 con = __raw_readl(base + OFF_GPCON);
77 con &= ~(0xf << con_4bit_shift(offset));
78 __raw_writel(con, base + OFF_GPCON);
79
80 return 0;
81}
82
83static int s3c64xx_gpiolib_4bit_output(struct gpio_chip *chip,
84 unsigned offset, int value)
85{
86 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
87 void __iomem *base = ourchip->base;
88 unsigned long con;
89 unsigned long dat;
90
91 con = __raw_readl(base + OFF_GPCON);
92 con &= ~(0xf << con_4bit_shift(offset));
93 con |= 0x1 << con_4bit_shift(offset);
94
95 dat = __raw_readl(base + OFF_GPDAT);
96 if (value)
97 dat |= 1 << offset;
98 else
99 dat &= ~(1 << offset);
100
101 __raw_writel(dat, base + OFF_GPDAT);
102 __raw_writel(con, base + OFF_GPCON);
103 __raw_writel(dat, base + OFF_GPDAT);
104
105 return 0;
106}
107
108/* The next set of routines are for the case where the GPIO configuration
109 * registers are 4 bits per GPIO but there is more than one register (the
110 * bank has more than 8 GPIOs.
111 *
112 * This case is the similar to the 4 bit case, but the registers are as
113 * follows:
114 *
115 * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs)
116 * gpio n: 4 bits starting at (4*n)
117 * 0000 = input, 0001 = output, others mean special-function
118 * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs)
119 * gpio n: 4 bits starting at (4*n)
120 * 0000 = input, 0001 = output, others mean special-function
121 * base + 0x08: Data register, 1 bit per gpio
122 * bit n: data bit n
123 *
124 * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we
125 * store the 'base + 0x4' address so that these routines see the data
126 * register at ourchip->base + 0x04.
127*/
128
129static int s3c64xx_gpiolib_4bit2_input(struct gpio_chip *chip, unsigned offset)
130{
131 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
132 void __iomem *base = ourchip->base;
133 void __iomem *regcon = base;
134 unsigned long con;
135
136 if (offset > 7)
137 offset -= 8;
138 else
139 regcon -= 4;
140
141 con = __raw_readl(regcon);
142 con &= ~(0xf << con_4bit_shift(offset));
143 __raw_writel(con, regcon);
144
145 return 0;
146
147}
148
149static int s3c64xx_gpiolib_4bit2_output(struct gpio_chip *chip,
150 unsigned offset, int value)
151{
152 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
153 void __iomem *base = ourchip->base;
154 void __iomem *regcon = base;
155 unsigned long con;
156 unsigned long dat;
157
158 if (offset > 7)
159 offset -= 8;
160 else
161 regcon -= 4;
162
163 con = __raw_readl(regcon);
164 con &= ~(0xf << con_4bit_shift(offset));
165 con |= 0x1 << con_4bit_shift(offset);
166
167 dat = __raw_readl(base + OFF_GPDAT);
168 if (value)
169 dat |= 1 << offset;
170 else
171 dat &= ~(1 << offset);
172
173 __raw_writel(dat, base + OFF_GPDAT);
174 __raw_writel(con, regcon);
175 __raw_writel(dat, base + OFF_GPDAT);
176
177 return 0;
178}
179
180static struct s3c_gpio_chip gpio_4bit[] = {
181 {
182 .base = S3C64XX_GPA_BASE,
183 .chip = {
184 .base = S3C64XX_GPA(0),
185 .ngpio = S3C64XX_GPIO_A_NR,
186 .label = "GPA",
187 },
188 }, {
189 .base = S3C64XX_GPB_BASE,
190 .chip = {
191 .base = S3C64XX_GPB(0),
192 .ngpio = S3C64XX_GPIO_B_NR,
193 .label = "GPB",
194 },
195 }, {
196 .base = S3C64XX_GPC_BASE,
197 .chip = {
198 .base = S3C64XX_GPC(0),
199 .ngpio = S3C64XX_GPIO_C_NR,
200 .label = "GPC",
201 },
202 }, {
203 .base = S3C64XX_GPD_BASE,
204 .chip = {
205 .base = S3C64XX_GPD(0),
206 .ngpio = S3C64XX_GPIO_D_NR,
207 .label = "GPD",
208 },
209 }, {
210 .base = S3C64XX_GPE_BASE,
211 .chip = {
212 .base = S3C64XX_GPE(0),
213 .ngpio = S3C64XX_GPIO_E_NR,
214 .label = "GPE",
215 },
216 }, {
217 .base = S3C64XX_GPG_BASE,
218 .chip = {
219 .base = S3C64XX_GPG(0),
220 .ngpio = S3C64XX_GPIO_G_NR,
221 .label = "GPG",
222 },
223 }, {
224 .base = S3C64XX_GPM_BASE,
225 .chip = {
226 .base = S3C64XX_GPM(0),
227 .ngpio = S3C64XX_GPIO_M_NR,
228 .label = "GPM",
229 },
230 },
231};
232
233static struct s3c_gpio_chip gpio_4bit2[] = {
234 {
235 .base = S3C64XX_GPH_BASE + 0x4,
236 .chip = {
237 .base = S3C64XX_GPH(0),
238 .ngpio = S3C64XX_GPIO_H_NR,
239 .label = "GPH",
240 },
241 }, {
242 .base = S3C64XX_GPK_BASE + 0x4,
243 .chip = {
244 .base = S3C64XX_GPK(0),
245 .ngpio = S3C64XX_GPIO_K_NR,
246 .label = "GPK",
247 },
248 }, {
249 .base = S3C64XX_GPL_BASE + 0x4,
250 .chip = {
251 .base = S3C64XX_GPL(0),
252 .ngpio = S3C64XX_GPIO_L_NR,
253 .label = "GPL",
254 },
255 },
256};
257
258static struct s3c_gpio_chip gpio_2bit[] = {
259 {
260 .base = S3C64XX_GPF_BASE,
261 .chip = {
262 .base = S3C64XX_GPF(0),
263 .ngpio = S3C64XX_GPIO_F_NR,
264 .label = "GPF",
265 },
266 }, {
267 .base = S3C64XX_GPI_BASE,
268 .chip = {
269 .base = S3C64XX_GPI(0),
270 .ngpio = S3C64XX_GPIO_I_NR,
271 .label = "GPI",
272 },
273 }, {
274 .base = S3C64XX_GPJ_BASE,
275 .chip = {
276 .base = S3C64XX_GPJ(0),
277 .ngpio = S3C64XX_GPIO_J_NR,
278 .label = "GPJ",
279 },
280 }, {
281 .base = S3C64XX_GPN_BASE,
282 .chip = {
283 .base = S3C64XX_GPN(0),
284 .ngpio = S3C64XX_GPIO_N_NR,
285 .label = "GPN",
286 },
287 }, {
288 .base = S3C64XX_GPO_BASE,
289 .chip = {
290 .base = S3C64XX_GPO(0),
291 .ngpio = S3C64XX_GPIO_O_NR,
292 .label = "GPO",
293 },
294 }, {
295 .base = S3C64XX_GPP_BASE,
296 .chip = {
297 .base = S3C64XX_GPP(0),
298 .ngpio = S3C64XX_GPIO_P_NR,
299 .label = "GPP",
300 },
301 }, {
302 .base = S3C64XX_GPQ_BASE,
303 .chip = {
304 .base = S3C64XX_GPQ(0),
305 .ngpio = S3C64XX_GPIO_Q_NR,
306 .label = "GPQ",
307 },
308 },
309};
310
311static __init void s3c64xx_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
312{
313 chip->chip.direction_input = s3c64xx_gpiolib_4bit_input;
314 chip->chip.direction_output = s3c64xx_gpiolib_4bit_output;
315}
316
317static __init void s3c64xx_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
318{
319 chip->chip.direction_input = s3c64xx_gpiolib_4bit2_input;
320 chip->chip.direction_output = s3c64xx_gpiolib_4bit2_output;
321}
322
323static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips,
324 int nr_chips,
325 void (*fn)(struct s3c_gpio_chip *))
326{
327 for (; nr_chips > 0; nr_chips--, chips++) {
328 if (fn)
329 (fn)(chips);
330 s3c_gpiolib_add(chips);
331 }
332}
333
334static __init int s3c64xx_gpiolib_init(void)
335{
336 s3c64xx_gpiolib_add(gpio_4bit, ARRAY_SIZE(gpio_4bit),
337 s3c64xx_gpiolib_add_4bit);
338
339 s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2),
340 s3c64xx_gpiolib_add_4bit2);
341
342 s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit), NULL);
343
344 return 0;
345}
346
347arch_initcall(s3c64xx_gpiolib_init);
diff --git a/arch/arm/plat-s3c64xx/include/plat/regs-gpio.h b/arch/arm/plat-s3c64xx/include/plat/regs-gpio.h
new file mode 100644
index 000000000000..75b873d82808
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/include/plat/regs-gpio.h
@@ -0,0 +1,35 @@
1/* linux/arch/arm/plat-s3c64xx/include/mach/regs-gpio.h
2 *
3 * Copyright 2008 Openmoko, Inc.
4 * Copyright 2008 Simtec Electronics
5 * Ben Dooks <ben@simtec.co.uk>
6 * http://armlinux.simtec.co.uk/
7 *
8 * S3C64XX - GPIO register definitions
9 */
10
11#ifndef __ASM_PLAT_S3C64XX_REGS_GPIO_H
12#define __ASM_PLAT_S3C64XX_REGS_GPIO_H __FILE__
13
14/* Base addresses for each of the banks */
15
16#define S3C64XX_GPA_BASE (S3C64XX_VA_GPIO + 0x0000)
17#define S3C64XX_GPB_BASE (S3C64XX_VA_GPIO + 0x0020)
18#define S3C64XX_GPC_BASE (S3C64XX_VA_GPIO + 0x0040)
19#define S3C64XX_GPD_BASE (S3C64XX_VA_GPIO + 0x0060)
20#define S3C64XX_GPE_BASE (S3C64XX_VA_GPIO + 0x0080)
21#define S3C64XX_GPF_BASE (S3C64XX_VA_GPIO + 0x00A0)
22#define S3C64XX_GPG_BASE (S3C64XX_VA_GPIO + 0x00C0)
23#define S3C64XX_GPH_BASE (S3C64XX_VA_GPIO + 0x00E0)
24#define S3C64XX_GPI_BASE (S3C64XX_VA_GPIO + 0x0100)
25#define S3C64XX_GPJ_BASE (S3C64XX_VA_GPIO + 0x0120)
26#define S3C64XX_GPK_BASE (S3C64XX_VA_GPIO + 0x0800)
27#define S3C64XX_GPL_BASE (S3C64XX_VA_GPIO + 0x0810)
28#define S3C64XX_GPM_BASE (S3C64XX_VA_GPIO + 0x0820)
29#define S3C64XX_GPN_BASE (S3C64XX_VA_GPIO + 0x0830)
30#define S3C64XX_GPO_BASE (S3C64XX_VA_GPIO + 0x0140)
31#define S3C64XX_GPP_BASE (S3C64XX_VA_GPIO + 0x0160)
32#define S3C64XX_GPQ_BASE (S3C64XX_VA_GPIO + 0x0180)
33
34#endif /* __ASM_PLAT_S3C64XX_REGS_GPIO_H */
35